Skip to content

id(web): a table cell with two paragraphs is fused into one word on save — paragraphs concatenated with no separator #1003

Closed

Description

@dezren39

Bug

In the id web editor's markdown ↔ ProseMirror codec (pkgs/id/src/web/markdown.rs), a table cell that contains more than one paragraph is fused into a single run of text on save — the paragraphs are concatenated with no separator at all, so words merge:

ProseMirror document (editor/collab-originated; a user pressing Enter inside a cell produces exactly this shape):

{"type":"table_cell","content":[
  {"type":"paragraph","content":[{"type":"text","text":"first"}]},
  {"type":"paragraph","content":[{"type":"text","text":"second"}]}
]}

Saved markdown cell: | firstsecond | — "first" and "second" have become one word. Reparsing that output yields the single text node firstsecond; the paragraph boundary is unrecoverable.

Root cause (verified in code)

json_to_ast's table-cell special case (markdown.rs, the table_header/table_cell branch after the main match, ~:1080-1098 on main 3b9d159) unwraps each paragraph in the cell and appends its inline children directly to the cell node, in sequence, with nothing inserted between paragraphs. The markdown parse direction never produces multi-paragraph cells (GFM table cells are inline-only), so this only fires for editor-authored or collab-merged documents — which is precisely the population the unwrap special case exists to serve (its own comment: "ProseMirror wraps cell content in paragraphs, so we unwrap them here").

Verified repro (this run, main 3b9d159)

Standalone verbatim-codec probe (evidence log: goal hidden_files/probe-2026-10-26-1415/out4.log, case cell-two-paras):

  • Input PM: header h, one data cell with paragraphs first and second (JSON in the log).
  • prosemirror_to_markdown → "| h |\n| --- |\n| firstsecond |\n".
  • Reparse → cell text is the single node firstsecond; SAMEPM: false.

Why it matters

Silent content corruption (word fusion) on save for anyone who puts a line break / second paragraph in a table cell in the editor — the same codec data-loss family as #996/#997, in the save direction's cell handling rather than the parse direction.

Suggested fix

In the cell unwrap loop, insert a separator between consecutive paragraphs — a single space is the least-surprise choice for a GFM cell (a literal newline cannot appear in a table row, and <br> would change rendering semantics); alternatively join with a space text node via append_inline_child so mark handling stays consistent. Whichever separator is chosen, pin it with a test so the behaviour is deliberate rather than accidental.

Acceptance criteria

  • A table cell with two paragraphs saves with a separator between them (no word fusion) and reparses to text containing both words as separate words.
  • Single-paragraph cells (the common case, and everything the markdown parse direction produces) save byte-identically to today.
  • A cell with three paragraphs, and a header cell with two paragraphs, behave the same way.
  • Existing web::markdown table tests pass.

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
    on Oct 26, 2026
  2. developing-today commented on Oct 26, 2026

    @developing-today
    Contributor
  3. added
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    on Oct 26, 2026
  4. dezren39 commented on Oct 26, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job
    • Session / ID: new-issue-creator cron run 2026-10-26 14:10 CDT
    • Found via: filed this run
    • Task: Verified with a standalone verbatim-codec probe on main 3b9d159 (log hidden_files/probe-2026-10-26-1415/out4.log, case cell-two-paras): an editor-originated table cell with two paragraphs saves as firstsecond — json_to_ast's cell unwrap loop inserts no separator between paragraphs. Enqueued as a triage packet to repo-health-code-pilot.
    • Expectation: triage confirms the separator choice (single space suggested in the issue); done when multi-paragraph cells save without word fusion and single-paragraph cells are byte-identical to today.
    • Links: probe evidence in goal hidden_files (see issue body)
  5. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 31, 2026
  6. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

    • Agent: repo-worker-code (OpenChamber scheduled lane)
    • Session / ID: task 1168
    • Task: Revalidate and triage multi-paragraph table-cell serialization.
    • Expectation: Confirm current behavior and ownership, then fix or route safely.
  7. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  8. added
    effort/sSmall: expected under 2 hours of work
    mode/onlineFully doable remotely: design, config, code, cloud
    on Nov 1, 2026
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/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/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