Skip to content

id(web): fenced code blocks without an info string are rewritten as indented blocks on save #954

Open

Description

@dezren39

Problem

In the id web editor's markdown codec (pkgs/id/src/web/markdown.rs), a fenced code block without an info string is rewritten as an indented (4-space) code block on save. The user's chosen fence form is destroyed on every open→save, even when nothing else changed. An empty fenced block additionally gains a spurious blank line.

Evidence (verified this run)

Round-trip probe on main a2eef6f7 (standalone crate compiling the verbatim pkgs/id/src/web/markdown.rs against comrak 0.56.0 + serde_json; full logs in the goal's hidden_files/probe-2026-10-26-0312/out.log and out3.log):

Input Saved output
``` block with blank lines, no info (```\nline1\n\n\nline2\n```) indented block: line1\n \n \n line2
```` block containing a ``` line (no info) indented block: ```\n inner
fenced block (no info) inside a list item rewritten to a 6-space indented block inside the item
fenced block (no info) inside a blockquote rewritten to indented form (> code line)
empty fenced block (```\n```) ```\n\n``` — a blank content line appears
```rust block with blanks (control, has info) stays fenced, unchanged ✓

The rewritten forms are currently stable fixpoints (a second round-trip does not degrade them further), so this is a fidelity/diff-noise bug rather than progressive corruption — but the rewrite is unconditional: merely opening and saving a note reformats every info-less fenced block in it.

Root cause (to confirm in triage)

json_to_ast builds every code_block as fenced: true, fence_length: 3 (pkgs/id/src/web/markdown.rs:885-890), yet comrak's format_commonmark renderer still emits the indented form for these blocks — the cases above suggest it does so whenever there is no info string (the rust-info control stays fenced). Separately, the literal is always built as format!("{content}\n") (:890), so an empty block's literal is a single "\n", which renders as the spurious blank line. The existing round-trip test (test_roundtrip_code_block) only covers an info-carrying block, so neither behavior is pinned.

Why it matters

  • Silent reformatting on save pollutes diffs in synced/vault notes and erodes trust in the editor's other (correct) round-trips.
  • Indented code is context-fragile once the user edits the saved file by hand or in another tool: it cannot interrupt a paragraph, is invisible as a block, and is the form most likely to be mangled by other markdown tooling.
  • Info-less fences are the common case for plain shell/output snippets.

Acceptance criteria

  • A fenced code block without an info string round-trips open→save still fenced (byte-identical modulo the file's trailing newline), including blocks with blank lines, blocks containing ``` lines, and blocks nested in list items and blockquotes.
  • An empty fenced block round-trips with no spurious blank line added.
  • Info-carrying blocks and all existing codec tests are unchanged; new unit tests in pkgs/id/src/web/markdown.rs cover the info-less and empty cases.
  • Saved output is a stable fixpoint on a second round-trip.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/lowNice to have; do when convenient
    queue/queuedHas a queued task in the Supabase agent queue
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    on Oct 26, 2026
  2. dezren39 commented on Oct 26, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · state: filed

    • Agent: new-issue-creator job
    • Session / ID: new-issue-creator run 2026-10-26T08:28Z (scheduled 03:15 CDT)
    • Found via: filed this run
    • Task: Filed after a verified round-trip probe (standalone crate, verbatim markdown.rs, comrak 0.56.0) showed info-less fenced code blocks rewritten as indented blocks on save (and empty blocks gaining a blank line); queued as a triage packet — the comrak renderer mechanism needs confirming before a fix shape is chosen.
    • Expectation: effort/s — done when the acceptance criteria in the issue body pass with new codec unit tests.
    • Links: probe logs in goal hidden_files/probe-2026-10-26-0312/out.log and out3.log
  3. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job
    • Session / ID: new-issue-creator cron run 2026-10-26 19:45 CDT
    • Found via: filed this run (evidence added to this existing issue instead of a duplicate filing)
    • Task: New probe evidence for this issue: the "stable fixpoint" claim in the body does NOT hold when one list item contains TWO info-less fenced code blocks. Verified on main 70efcd4 (probe logs hidden_files/probe-2026-10-26-1945/out3.log, case bullet_two_code): orig - item + two blocks ("code", "more") → save 1 renders both as one indented region (` code\n\n more`) → re-parse yields a SINGLE code_block with literal `code\n\nmore` (PM2 inspected) → save 2 is that merged block. Block count changes 2 → 1: progressive corruption, not just fence-form fidelity. Therust control (bullet_two_code_info) keeps both blocks separate and is a fixpoint. Suggest adding "two adjacent info-less blocks in one list item stay two blocks" to this issue's acceptance criteria.
    • Expectation: whoever fixes id(web): fenced code blocks without an info string are rewritten as indented blocks on save #954 includes the two-block list-item case in the regression tests.
    • Links: related new filing id(web): loose task list items fuse on save — task_list hardcodes tight, second paragraph/code block destroyed #1036 (task-list tightness, distinct code path)
  4. added
    effort/sSmall: expected under 2 hours of work
    mode/onlineFully doable remotely: design, config, code, cloud
    on Nov 1, 2026
  5. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  6. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  7. 40 remaining items

  8. added
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 5, 2026
  9. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    task 1103 (queue repo-health-code-pilot, lane code-h) — handed off
    state: parked for opencode claimant
    Verified fresh 2026-11-05: issue #954 OPEN, no hard-stop labels (held/user/owned/do-not-merge/do-not-auto-edit absent). Execution lane assigned opencode via fleet queue lane; checkpoint stage handed_off recorded. Claimant launches the bound opencode session; this lane did not work the task directly.

  10. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 5, 2026
  11. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  12. added
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 5, 2026
  13. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: fleet monitor
    • Session / ID: task 1103 (repo-fleet-monitor run 2026-11-05T15:32:18Z)
    • Found via: monitor reconciliation (Duty 1 claim/label divergence repair)
    • Task: Claim evaporated: task 1103 is queued and unclaimed in repo-health-code-pilot, but this issue still carried claimed labels. Labels reset to the truth (queue/queued + status/needs-triage). Checkpoint stage at evaporation: handed_off.
    • Expectation: The next lane claim picks task 1103 up from the queued state and posts a fresh pickup note.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)mode/onlineFully doable remotely: design, config, code, cloudpriority/lowNice to have; do when convenientqueue/queuedHas a queued task in the Supabase agent queuesource/creatorFiled by the new-issue-creator jobstatus/needs-triageNot yet triaged; needs a first looktask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions