Repository navigation
Description
Summary
The #1019 fix for spaced link/image destinations only triggers on a literal space. Destinations containing a tab (authored or editor-originated) or a newline (editor-originated) take the unprotected path and are destroyed on save:
- Tab:
[x](</a\tb>)parses to a link with href/a\tb, but saves as[x](/a% 9b)— comrak emits a%, a space, and a partial hex digit, which is not valid percent-encoding at all. On reopen the link is gone: the saved text parses as plain text. Images (→) and reference definitions ([r]: </a\tb>) fail identically. - Newline (PM-originated): a link mark whose href contains
\n(e.g. set via the editor) saves as[x](/a% Ab)and likewise reopens as plain text; an image whose src contains\nsaves aswith the same result.
Evidence
Verified on main 37418e56 with a verbatim-codec probe crate (comrak 0.56.0, compiled and run on the laptop; logs hidden_files/probe-2026-10-27-1027-laneA-out.log (probe8) and the probe9 run, cases probe-2026-10-27-1027-laneA-probe8.rs / probe9.rs):
=== angle-dest-tab pm_same=false
IN : "[x](</a\tb>)\n" PM: link mark href "/a\tb"
OUT: "[x](/a% 9b)\n" PM2: plain text "[x](/a% 9b)" <- link destroyed, non-fixpoint
=== image-angle-dest-tab / ref-def-angle-tab / pm-link-href-tab / pm-image-src-tab: identical pattern
=== pm-image-src-newline pm_same=false
PM : image src "/x\nb.png"
OUT: "\n" PM2: plain text <- image destroyed
(PM link href "/a\nb" behaves the same: OUT "[x](/a% Ab)\n", PM2 plain text.)
A direct comrak parse→render control produces the same % 9 output for the tab case, so the mangling itself is the renderer's — the codec defect is that its #1019 protection does not cover these destinations, exactly as it did not cover spaces before #1019.
Scope correction vs. the original filing: an authored angle-bracket destination containing a raw newline ([x](</a\nb>)) is not parsed as a link by comrak in the first place (it is plain text on both parse and save), so there is no authored-newline corruption — the newline case is editor-originated hrefs/srcs only. The tab case affects authored files directly.
Root cause
pkgs/id/src/web/markdown.rs:1091 — substitute_spaced_destinations (the #1019 placeholder mechanism, :1081-:1112) skips any destination that does not contain a space:
if !url.contains(' ') {
continue;
}Tab- and newline-bearing destinations therefore reach comrak's renderer unprotected. The placeholder-restore step writes the raw destination back in angle form <{raw}> (:1070-:1072), which represents tabs byte-identically (the probe's first parse proves [x](</a\tb>) parses to exactly that href). One caution: a destination containing a newline and literal document text matching the placeholder pattern interacts with #1348 (placeholder collision); the widened trigger should keep the placeholder tokens collision-safe.
Why it matters
Angle-bracket destinations exist precisely for destinations the bare form cannot represent. A filename containing a tab is unusual but legal on Linux, and such a document is silently corrupted by simply opening it in the id web editor and saving — the link/image does not just get rewritten, it stops being a link/image at all. Same silent-corruption class as #1019, one whitespace character over.
Acceptance criteria
-
[x](</a\tb>),, and the reference-definition form round-trip open → save → open with the href/src byte-identical and the link/image intact (saved in angle form, no% 9). - Editor-originated destinations with a tab or newline (link mark href, image src) round-trip with the link/image intact on reopen.
- Regression tests in
pkgs/id/src/web/markdown.rscover tab destinations (link, image, reference definition) and newline destinations (PM-originated link/image); existingweb::markdowntests (including the id(web): link/image destinations with a space are silently rewritten to %20 on save — angle-bracket form lost, relative file links break #1019 spaced-destination tests) still pass. - The fix does not regress id(web): spaced-destination placeholder can collide with document text — global replace on save rewrites the document's own words (PR #1022) #1348's placeholder-collision concern (placeholder tokens remain unguessable / collision-checked).
Relates to: #1019 (space case, fixed), #1348 (placeholder collision).
Activity
developing-today commentedon Oct 27, 2026
CODE-512
dezren39 commentedon Oct 27, 2026
🤖 Agent note · filed
dezren39 commentedon Oct 27, 2026
🤖 Agent note · correction
[x](/a% 9b)— a%, a space, and a partial hex digit — not%09, and the link/image is destroyed on reopen (plain text), not merely mutated. Verified for authored angle links/images/reference definitions and editor-originated hrefs/srcs (probe8 + probe9, laptop, main 37418e5). (2) The newline case is editor-originated only: an authored[x](</a\nb>)is not parsed as a link by comrak at all (plain text both ways), so there is no authored-newline corruption; a PM link href / image src containing\ndoes save as the broken% A…form and loses the link/image on reopen. The core defect and fix direction are unchanged: substitute_spaced_destinations (markdown.rs:1091) only protects destinations containing a literal space. Queue packet 1425 carries the original wording in its body text; this comment + the edited issue body are canonical.177 remaining items
dezren39 commentedon Oct 28, 2026
🤖 Agent note · parked
dezren39 commentedon Oct 28, 2026
🤖 Agent note · picked up
Merge pull request #1543 from developing-today/queue/1489-1423-spaced…
dezren39 commentedon Oct 28, 2026
🤖 Agent note · done
nix flake checksummary job remained QUEUED (created 08:49Z after its constituents finished) — merged under the standing directive after verifying every constituent green, same pattern as PR 1559 earlier this shift.