Repository navigation
Description
Problem
In pkgs/id's web markdown codec, whitespace at the edges of a text run — state the rich editor readily holds — is written to the saved file but cannot survive the codec's own reparse. CommonMark strips up to three leading spaces on a paragraph line and ignores trailing spaces, so on the next open the spaces are gone. The worst case is structural: a paragraph whose only content is spaces is deleted outright on reopen, collapsing the document's block structure.
Verified on main 37418e56 with a verbatim-codec probe crate (comrak 0.56.0, compiled and run on the laptop; PM-first cases in hidden_files/probe-2026-10-27-0927-laneA-out2.log + out3.log):
| PM document | Saved file | After reopen |
|---|---|---|
paragraph leading spaces |
leading spaces |
leading spaces — 2 spaces lost |
paragraph foo (trailing) |
foo |
foo — trailing spaces lost |
paragraphs [ , x] |
+ blank + x |
only x — the whitespace-only paragraph is gone |
foo + hard_break + bar |
foo\ + newline + bar |
foo + hard_break + bar — spaces after the break lost |
table header A, cell x |
| A | / | x | |
A / x — cell padding lost |
All five are non-fixpoint across a full open→save→open cycle (the second save differs from the first: e.g. leading spaces → leading spaces; the space-only case loses a whole block). Note the saved bytes look correct — the loss happens on reopen, because the codec emits plain spaces for state markdown cannot represent (compare the mark-wrapper path, which protects edge spaces with   entities — no equivalent protection exists for unmarked run edges).
Why it matters
Users typing in the rich editor create this state without doing anything exotic: indenting a paragraph's first line with spaces (a common writing habit), trailing spaces, or an empty spacer paragraph made of spaces. The editor shows one document, the file on disk appears to match it, and the next open silently shows a different one — in the spacer-paragraph case with a block deleted. Even where the resolution is "markdown cannot represent this, normalize it away", that normalization should happen at save (visibly, as a fixpoint) rather than as a silent reopen-time loss, and the whitespace-only paragraph deserves an explicit decision (map to an empty paragraph representation? drop at save?) instead of the current emergent deletion.
Acceptance criteria
- A policy is picked and pinned for edge whitespace in unmarked text runs (paragraph start/end, after hard_break, table cells): either preserved across open→save→open, or normalized at save so the first saved file is already a byte fixpoint and the editor-visible result is the documented one.
- The whitespace-only paragraph case is explicitly decided: it must not silently vanish on reopen — either it round-trips (e.g. as an empty paragraph) or the save direction drops/normalizes it so file and reopen agree from the first save.
- The five probe cases above are covered by regression tests in
pkgs/id/src/web/markdown.rs; existingweb::markdowntests pass, and the protection for marked spans (cf. id(web): a marked span starting or ending with a space loses its mark on reopen when a word character touches it — saved   form cannot reparse #1418) is unaffected.
Related: #1418 (the marked-span counterpart — edge spaces inside delimiters), #1045 (unknown-mark policy — same pick-and-pin-a-policy shape), #1307 (.txt byte-faithfulness, different mode).
Activity
developing-today commentedon Oct 27, 2026
CODE-509
dezren39 commentedon Oct 27, 2026
🤖 Agent note · filed
54 remaining items
dezren39 commentedon Oct 28, 2026
🤖 Agent note · picked up
fix(id): normalize unmarked text-run edge whitespace at save (#1420) (#…
dezren39 commentedon Oct 28, 2026
🤖 Agent note · done