Skip to content

id(web): inline markup inside image alt text is stripped on save — emphasis and code spans flattened to plain text #1417

Closed

Description

@dezren39

Problem

In pkgs/id's web markdown codec, any inline markup inside an image's alt text is silently stripped on the first open→save: emphasis, strong, code spans, and nested links in the description are flattened to their plain text. The saved file no longer matches what the author wrote, and for code spans the flattening changes the literal alt text other renderers display.

Verified on main 37418e56 with a verbatim-codec probe crate (comrak 0.56.0; hidden_files/probe-2026-10-27-0854-laneA/out.log + out3.log):

Input Saved
![*alt* text](/x.png) ![alt text](/x.png)
![**bold alt**](/x.png) ![bold alt](/x.png)
![a `code` b](/x.png) ![a code b](/x.png)
![a [link](/y) b](/x.png) ![a link b](/x.png)

Controls in the same probe: a direct comrak parse→format_commonmark round-trip with the codec's own options preserves every one of these byte-for-byte (![*alt* text](/x.png), ![a `code` b](/x.png)), so this is a codec loss, not a comrak renderer behaviour. Alt text containing an escaped bracket (![a\]b](/x.png)) and entities round-trip fine — only markup structure is lost.

Root cause

Parse direction, pkgs/id/src/web/markdown.rs:354-360 (the NodeValue::Image arm of convert_node): the alt is extracted with get_text_content(node) (:710), which concatenates only the text literals of the alt subtree. The PM image node stores alt as a plain string, so the markup is gone before the save direction (:1308, which re-emits the stored string as the image's text child) ever runs.

Why it matters

Alt text with emphasis or code spans is ordinary in imported notes and documentation (e.g. ![the `resize` handler](/img.png)). The loss is silent, happens on an untouched open→save, and is a stable fixpoint afterwards, so nothing downstream notices. It is the inside-the-image counterpart of #1407 (marks around an image); the two share the image node but have different root causes and fixes.

Acceptance criteria

  • ![*alt* text](/x.png), ![**bold alt**](/x.png), and ![a `code` b](/x.png) round-trip with the alt markup preserved (exact markdown, or a form that re-parses to the same alt structure and renders the same alt text).
  • The chosen representation is coherent with how the editor treats alt as a plain string attribute today (pkgs/id/web/src/editor.ts image node): either the codec stores a markdown-form alt and re-parses it on save, or another representation is picked and any editor-side limitation is documented in the resolution.
  • Nested-link alt (![a [link](/y) b](/x.png)) is either preserved or explicitly decided and documented (it is invalid in some renderers — a documented flattening for this one case is acceptable if the emphasis/code cases above are fixed).
  • Regression tests in pkgs/id/src/web/markdown.rs cover emphasis, strong, and code-span alt text in both directions; existing web::markdown tests pass.

Related: #1407 (marks wrapping an image — different root cause), #880 (linked images), #1045 (unknown-mark policy).

Activity

  1. developing-today commented on Oct 27, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 27, 2026
  3. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (lane A, new-issue-creator-code-a)
    • Session / ID: new-issue-creator-code-a cron run, 2026-10-27 08:54 CDT
    • Found via: filed this run
    • Task: Triage/fix image alt-text markup loss in the web markdown codec (parse Image arm flattens the alt subtree via get_text_content, markdown.rs:354-360/:710)
    • Expectation: effort/s — codec representation decision (markdown-form alt vs alternative) plus regression tests both directions; done when the acceptance criteria on the issue pass
    • Links: probe evidence hidden_files/probe-2026-10-27-0854-laneA/out.log + out3.log (goal workspace); related id(web): emphasis/strong/strikethrough wrapping an image are silently dropped on save — mixed text+image spans split and leak   entities #1407 (marks around an image — different root cause)
  4. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  5. added
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 27, 2026
  6. 39 remaining items

  7. added
    status/parkedDeliberately paused with a recorded resume condition
    on Oct 27, 2026
  8. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  9. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 28, 2026
  10. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  11. added a commit that references this issue on Oct 28, 2026
  12. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobstatus:donetask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions