githubnext/chopinPublic

Let's compose rich plans together

Drop empty paragraphs from canonical document projection #212

Mergedlavaman131merged 1 commit intomainfromrefs/pull/212/head
  1. LA

    Closes #211

    ## Problem

    An empty Lexical paragraph was exported as an MDAST `paragraph` with no children. `serialize` writes that as an extra blank line, and `parse` discards it. Pressing Enter at the end of a document, or inserting a `/research` card, was enough to make the room persist source that fails its own round trip. The `document-summary` job then failed with "Document source is not canonical." under every harness.

    ## Change

    - `packages/dialect/src/convert.ts`: `$exportPlanTree` drops empty paragraphs at every depth, so projection is canonical. Block addressing already ignored them: `addressable()` skips root-level empty paragraphs and `digests()` goes through `parse`. The Lexical tree and browser editing are unchanged; only the server projection differs. Table cells and a container left with only an empty paragraph export exactly as before. - `apps/server/src/plan/room.ts`: existing checkpoints still store the old blank lines, and `restore()` required the stored source to match the projection exactly. Without a change, those channels would fail to open with "stored plan source does not match its Yjs checkpoint". `restore()` now also accepts a stored source whose canonical form, `serialize(parse(source))`, matches the projection. An unrelated source is still rejected. The next checkpoint rewrites the source in canonical form.

    Existing documents keep failing description jobs until their next edit re-projects them.

    ## Verification

    New regression tests cover export at the root, after a Research card, between blocks and inside a blockquote, plus restoring a legacy checkpoint. Both failed before the fix.

    Live check with agent-browser against an `AGENT=off` server: I typed text and pressed Enter twice, then read the stored snapshot.

    | Checkout | Stored source | `serialize(parse(s)) === s` | |---|---|---| | `main` | `"The harp needs new strings.\n\n\n\n"` | false | | this branch | `"The harp needs new strings.\n"` | true |

    A document written by `main` opened on this branch without errors, accepted an edit, and was saved in canonical form (`"…strings.\n\nOrder a full set.\n"`):

    ![A main-written document edited on this branch](https://github.com/user-attachments/assets/7971313a-4af8-4b18-a764-d912e5ec56a5)

    The first run of `bun run e2e` failed one test, `responsive-decisions.e2e.ts` "long independent decisions…", on a strict-mode locator. That failure also happens on `main`: cold-start runs of that test failed 2 of 3 times on `main` and 3 of 3 on this branch, so it is an existing flake. The rerun of the full suite passed.

    Assistant-verification: bun test unit passed: 1659 pass, 2 skip, 0 fail; new convert and room regression tests failed before the fix Assistant-verification: bun run test:postgres passed: 59 PostgreSQL contract tests Assistant-verification: bun run types passed: all workspaces and E2E Assistant-verification: bun run ci passed: dprint, oxlint, tokens, type scale, Impeccable Assistant-verification: bun run e2e passed: 236 Chromium tests on rerun; the one earlier failure is an existing cold-start flake that also fails on main Assistant-verification: agent-browser E2E passed: text plus two Enters stores canonical source on this branch versus non-canonical on main; a main-written document opens, edits, and re-persists canonically Assistant-model: Claude Opus 5.5 Assistant-workflow: inline Assistant-duration: 16m converged, estimated none given Co-authored-by: Alex Lavaee <lavaman131@github.com>

  2. lavaman131assigned lavaman131last month on GitHub

  3. lavaman131head-ref-force-pushed 908f1b773fdalast month on GitHub

  4. MaggieAppletonreferenced 8c74c164075dlast month on GitHub

  5. MA

    No review summary.

  6. lavaman131head-ref-force-pushed e1fc8c359de2last month on GitHub

  7. MA

    all good

  8. MaggieAppletonhead-ref-force-pushed cd0242ecbcfblast month on GitHub

  9. MaggieAppletonmerged bae781859789last month on GitHub

  10. MaggieAppletonclosedlast month on GitHub

  11. MaggieAppletonhead-ref-deletedlast month on GitHub

  12. MaggieAppletonreferenced this in Add an Atomic SDK harness for the hosted Planner #210last month on GitHub

  13. lavaman131referenced adb413ed4b01last month on GitHub