Skip to content

id(web/markdown): HTML <img> width/height that aren't bare integers are silently dropped on markdown import — 200px, 50%, 200.0 sizing vanishes with no trace #2180

Closed

Description

@dezren39

id(web/markdown): HTML <img> width/height that aren't bare integers are silently dropped on markdown import — 200px, 50%, 200.0 sizing vanishes with no trace

Evidence (verified this run, main c58507a3)

pkgs/id/src/web/markdown.rs:1208-1217 (parse_img_tag, the #893 HTML-image import path):

if let Some(w) = attr("width")
    && let Ok(n) = w.parse::<u64>()
{
    attrs["width"] = json!(n);
}
if let Some(h) = attr("height")
    && let Ok(n) = h.parse::<u64>()
{
    attrs["height"] = json!(n);
}

A dimension that fails the bare-u64 parse is not rejected, not preserved, and not reported — the attribute simply never enters the ProseMirror node. On the next save, prosemirror_to_markdown (markdown.rs:1953-1968) emits dimensions only from attrs.width/attrs.height, so the sizing is gone from the document permanently.

Verbatim-probe (laptop, ~/git/fleet/probe-2026-10-29-laneA-imgwidth/, parse_tag_attrs + parse_img_tag copied from main c58507a3):

input resulting attrs
width="200" height="100" (control) width:200, height:100 — kept
width="200px" height="100px" both dropped
width="50%" dropped
width="200.0" dropped
width=" 200" (leading space) dropped
width="0" kept as 0
width="+200" kept as 200 (Rust u64 parse accepts a leading +)

200px is the form most of the world's HTML and Markdown-with-inline-HTML actually uses (CSS-style dimensions in exported notes, README badges, pasted web content); percentages are the standard responsive form. Both reach this parser through the raw-HTML image path (#893) and lose their sizing silently on the first load/save round-trip.

Why it matters

Acceptance criteria

  • Triage pins the dimension grammar for the markdown import path: which of 200px (strip a px suffix), 50% (percent — represent or refuse), 200.0, and whitespace-padded values are accepted, and what happens to the rest.
  • A dimension the pinned grammar refuses is not silently dropped: it is either preserved in the node or the import surfaces it (the pinned behavior is recorded on this issue).
  • Regression tests in web/markdown.rs cover the pinned grammar end-to-end (import → node attrs → markdown emission) for at least: bare integer (control), px-suffixed, fractional, and padded values.
  • No behavior change for images whose dimensions already parse as bare integers.

Dedup: #2010 is the TypeScript editor parseDOM path (bare Number() — NaN/fraction/hex pass through); #872 (closed) was substring attribute shadowing in this same function; #893 (closed) added the sized-image import form itself. None covers the Rust import-side dimension grammar.

Activity

  1. developing-today commented on Oct 29, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/lowNice to have; do when convenient
    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
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/xsTrivial: expected under 30 minutes of work
    on Oct 29, 2026
  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator-code-a (Lane A)
    • Session / ID: cron job new-issue-creator-code-a, run 2026-10-29T07:35Z
    • Found via: filed this run
    • Task: Filed after verifying with a verbatim-copy probe (compiled/run on the laptop, ~/git/fleet/probe-2026-10-29-laneA-imgwidth/) that parse_img_tag (web/markdown.rs:1208-1217, main c58507a) silently drops any width/height that is not a bare u64: 200px/100px both dropped, 50% dropped, 200.0 dropped, " 200" dropped; control 200/100 kept, 0 and +200 kept. NOT self-solved: the dimension grammar (px-suffix, percent, fraction handling) is triage's pin.
    • Expectation: effort/xs — triage pins the dimension grammar, then a small-fix implements it with regression tests in web/markdown.rs.
    • Links: packet queue-pilot/packet-2180-triage.json (repo-health-code-pilot)
  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed on Nov 1, 2026
  5. 31 remaining items

  6. added
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 1, 2026
  7. added 2 commits that reference this issue on Nov 1, 2026
  8. removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    work/assignedQueue worker lifecycle state
    on Nov 1, 2026
  9. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: done
    task: 5201 (repo-health-code-pilot, lane D)
    stage: fixed_merged (resumed)
    did: PR #3408 merged (merge commit 199d9f2); this issue auto-closed. This shift committed and pushed the exact-decimal dimension parser (f68c96e) left uncommitted by the prior lane, verified web::markdown 119/119 on the laptop, replied to and resolved both Codex P2 threads, and confirmed a fresh Codex round on the final head with no findings before merging.
    resume: none — terminal.

  10. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  11. 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 Nov 1, 2026
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/xsTrivial: expected under 30 minutes of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/lowNice to have; do when convenientsource/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