Repository navigation
Description
Problem
In the id web markdown codec (pkgs/id/src/web/markdown.rs), a document where a list is immediately followed by a list of a different type — bullet → ordered, ordered → bullet, or task → bullet with no blank line between them — is corrupted on save: the save writes a literal <!-- end list --> HTML comment between the lists, and reopening the saved file turns that comment into a spurious code_block node sitting between the lists in the document model.
#1032 fixed this for adjacent bullet lists (different markers) by coalescing them on save. Different-type neighbours cannot be coalesced — a bullet list and an ordered list are genuinely different lists — so the boundary case #1032 excluded is still live.
Evidence (verified this run on main 452d69e6; markdown.rs identical at 95bfedb4 where the probe copy was taken)
Probe: verbatim copy of pkgs/id/src/web/markdown.rs in a standalone crate (comrak 0.56), markdown_to_prosemirror → prosemirror_to_markdown → re-parse. Log: fleet bookkeeping probe-2026-10-27-creator-a3/out4.log (cases also in out3.log).
| Input | Save output | Re-parsed PM |
|---|---|---|
- a\n1. b\n |
- a\n\n<!-- end list -->\n\n1. b\n |
bullet_list, code_block{params:"html", htmlBlock:true} containing <!-- end list -->, ordered_list |
1. a\n- b\n |
1. a\n\n<!-- end list -->\n\n- b\n |
ordered_list, same spurious code_block, bullet_list |
- a\n- b\n1. c\n2. d\n |
comment inserted at the type boundary | same spurious code_block between the lists |
1. [ ] t\n- plain\n |
1. [ ] t\n\n<!-- end list -->\n\n- plain\n |
task_list, same spurious code_block, bullet_list |
> - a\n> 1. b\n (inside blockquote) |
> - a\n> \n> <!-- end list -->\n> \n> 1. b\n |
spurious code_block inside the quote — and the second save is not even a markdown fixpoint (the blank > line before > 1. b is dropped) |
Root cause, both directions:
- Save:
json_to_ast's child loop coalesces only consecutivebullet_listsiblings (markdown.rs:1464-1487, the id(web): adjacent bullet lists with different markers accumulate '<!-- end list -->' comments and html fences on every save — non-fixpoint, grows per save #1032 fix; its comment notes ordered/task lists are deliberately untouched). Any other adjacent list-type pair is emitted as sibling comrakListnodes, and comrak's CommonMark renderer separates sibling lists of different types with an<!-- end list -->comment. - Parse: the comment comes back as an
HtmlBlock, and theNodeValue::HtmlBlockarm (markdown.rs:391-419, the id(web): HTML blocks (comments, <details>, <div>) are rewritten as ```html code blocks on save #982 fallback) converts it into acode_blockwithparams:"html"/htmlBlock:true. At the pure codec level the markdown then happens to re-emit the comment (so the text is a fixpoint outside blockquotes), but the document model has gained a block the user never wrote — in the editor that block presents as a code block wedged between the two lists, and any consumer of the PM doc (collab, API writers, future schema tightening) sees content that was never in the source.
Controls from the same probe: same-type adjacent lists (post-#1032), blank-line-separated lists, nested lists, and task/plain nested sublists all round-trip cleanly; only same-level different-type adjacency breaks.
Why it matters
Switching from bullets to numbered steps mid-document without a blank line is a common note-taking shape (a shopping list followed by numbered prep steps; an agenda followed by action items). Today the first save pollutes the file with a renderer-internal comment, and reopening shows a phantom code block between the lists — the same user-visible failure family #1032 was filed to eliminate, surviving at exactly the boundaries its fix could not merge.
Acceptance criteria
- All five shapes above save with no
<!-- end list -->comment (or any other renderer-internal separator) written into the user's markdown, and re-parse to a PM doc with exactly the two original lists and nothing between them. - The blockquote shape is a full markdown fixpoint across two saves.
- The chosen separation strategy is coherent with the id(web): adjacent bullet lists with different markers accumulate '<!-- end list -->' comments and html fences on every save — non-fixpoint, grows per save #1032 precedent and the id(web): HTML blocks (comments, <details>, <div>) are rewritten as ```html code blocks on save #982 HTML-block provenance design, with a note in the PR on what separates the lists in the saved text (e.g. a separator the parse direction provably drops, or a save-direction rewrite that avoids sibling different-type
Listnodes reaching the renderer). - id(web): adjacent bullet lists with different markers accumulate '<!-- end list -->' comments and html fences on every save — non-fixpoint, grows per save #1032 behaviour is unchanged: adjacent bullet lists still coalesce, and its regression tests keep passing; existing
web::markdowntests keep passing. - Regression tests in
pkgs/id/src/web/markdown.rscover bullet→ordered, ordered→bullet, task→bullet, and the blockquote case in both save and re-parse directions.
Activity
developing-today commentedon Oct 27, 2026
CODE-489
dezren39 commentedon Oct 27, 2026
🤖 Agent note · filed
<!-- end list -->comment that re-parses as a phantom htmlBlock code_block; blockquote shape is not a markdown fixpoint. id(web): adjacent bullet lists with different markers accumulate '<!-- end list -->' comments and html fences on every save — non-fixpoint, grows per save #1032 covered only coalescable bullet/bullet adjacency.dezren39 commentedon Oct 27, 2026
Evidence from new-issue-creator-code-a (2026-10-27 run, verbatim-codec probe on main 37418e5): the same phantom-block symptom triggers with two adjacent ordered lists that differ only in delimiter —
1. a\n2) b\nsaves as1. a\n\n<!-- end list -->\n\n2. b\nand reopens with acode_block(htmlBlock) containing<!-- end list -->inserted between the two lists. The delimiter loss itself is #1380; noting here that the end-list-comment → phantom-code-block mechanism in this issue is not limited to lists of different types — a delimiter change within ordered lists produces it too.154 remaining items
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off