Repository navigation
Description
Problem
A bold link in a markdown file flips its markdown spelling on every save in the id web editor — the markdown ↔ ProseMirror codec has no fixpoint for text carrying both strong and link marks:
- File contains
**[text](https://e.com)**→ open + save emits[**text**](https://e.com) - That output, opened + saved again, emits
**[text](https://e.com)**again - …and so on, forever. Every save of a document containing a bold link produces a spurious diff, even if the user changed nothing near the link.
Verified probe on main a2eef6f7 (standalone crate compiling the verbatim pkgs/id/src/web/markdown.rs codec from main; logs in the goal's hidden_files probe-2026-10-25-2312/probe2.log and probe3.log):
- MD→PM→MD case
link-in-strong: input**[text](https://e.com)**, PM marks[strong, link], save test #1[**text**](https://e.com), save Bump checkmarx/ast-github-action from 2.0.11 to 2.0.18 #2**[text](https://e.com)**—STABLE: false. - PM→MD case
link-strong-order2: PM marks[link, strong]→ save test #1**[text](https://e.com)**, reparse gives marks[strong, link], save Bump checkmarx/ast-github-action from 2.0.11 to 2.0.18 #2[**text**](https://e.com)—STABLE: false. - Control:
em+strong(***both***) round-trips stably, so this is specific to howlinkinteracts with the wrapper ordering.
Root cause (pointers)
The two directions disagree about mark nesting order for links:
- Parse direction:
convert_node'sNodeValue::Linkarm (markdown.rs:278) appends thelinkmark after marks already active from enclosing nodes (e.g.Strong, markdown.rs:268), so**[text](url)**yields marks[strong, link]. - Save direction:
create_marked_text/build_mark_chain(markdown.rs:1117 / 1167) treat the marks array as[innermost, …, outermost]and wrap in array order — for[strong, link]that buildsLink(Strong(text)), which comrak renders as[**text**](url), whose reparse yields the opposite nesting.
One of the two directions must change so that parse(emit(doc)) is a fixpoint for link+emphasis/strong combinations (or the PM marks must be canonicalised to a single agreed order in both directions).
Why it matters
Non-idempotent save means perpetual dirty diffs and needless revision churn for any doc with bold/italic links — a common pattern — and it makes "did my edit change anything else?" unanswerable from the diff. Same codec-fidelity family as #880/#881/#882, but a stability bug rather than data loss.
Acceptance criteria
**[text](url)**and[**text**](url)each reach a fixpoint: open → save → open → save produces byte-identical markdown after the first save, for both spellings.- Same fixpoint holds for
em+link(*[text](url)*/[*text*](url)). - Semantics unchanged: the link href/title and the strong/em emphasis survive every round-trip.
- New unit tests in
pkgs/id/src/web/markdown.rsassert two consecutive round-trips are identical for the strong+link and em+link cases.
Activity
developing-today commentedon Oct 26, 2026
CODE-156
dezren39 commentedon Oct 26, 2026
🤖 Agent note · filed
**[text](url)**-> save[**text**](url)-> save**[text](url)**again, STABLE: false in both directions (logs: goal hidden_files probe-2026-10-25-2312/probe2.log, probe3.log). Queued for the code pilot queue (small_fix packet).6 remaining items
dezren39 commentedon Oct 26, 2026
🤖 Agent note · picked up
Merge pull request #985 from developing-today/queue/1091-944-strong-l…
dezren39 commentedon Oct 26, 2026
🤖 Agent note · done