Skip to content

Two blog-SVG lines sit under 3px from their card edge, and nothing measures clearance — the near-miss tier of the #193 defect class #200

Description

@hotlong

Found while implementing #193. Unassigned; recording only.

(Tag names are written out rather than in angle brackets, per the note on #180 — the body sanitizer eats short tag-shaped fragments, backticks included.)

The gap

#193 repaired five text nodes that ran past their card edge or sat on a foreground graphic. The contrast harness finds those because a glyph that has left its card is standing on a different colour, and worst-ground-under-the-ink scores it.

That instrument is structurally blind to the same defect one pixel short of happening. A line that stops 2px inside its card is on exactly the intended ground, scores exactly its intended ratio, and is reported as perfectly healthy. Nothing in the repo measures the distance between a glyph box and the card that is supposed to contain it.

This matters here more than it would elsewhere because of what these files declare as their type face:

-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif

Every term in that stack resolves to a different face, and these SVGs are shipped to readers' browsers rather than rasterised at build time. The line lengths that CI measures on Linux/Chromium are not the line lengths a reader on macOS or Windows gets. A face 2% wider turns a 2px clearance into the #193 defect — on the reader's screen, never in CI.

What was measured

Every "text" node in content/blog/**/*.svg was loaded in Chromium at native size, and for each one the tightest rect that fully contains its glyph box was found and the clearance to that rect's nearer vertical edge recorded. 2,005 of the 2,009 nodes sit inside such a card.

Measured at 4cfecea — i.e. after #193's repairs, so these are what survives:

clearance card w file line
1.75px 440 why-custom-systems-die/cover-en.svg #13 1.8× the purchase price — scattered ac…
2.80px 200 ai-wrote-your-app-dare-to-merge/review-loop-en.svg #5 (dozens of lines, not thousands)
6.65px 100 automation-cross-system-flows/cross-system-flow-en.svg #8 effect: read
7.94px 160 airtable-style-ai-builder/cover-en.svg #2 Objects / views
9.55px 368 ai-wrote-your-app-dare-to-merge/cover-en.svg #4 +8,142 −0
9.63px 210 airtable-omni-vs-governed-ai-app-platform/cover-en.svg #13 ✓ Approve change

Under 6px: 2 nodes. Under 10px: 6 nodes. The rest of the corpus is comfortable, so this is a short list, not a sweep.

The second row is the one worth looking at twice: it is the neighbouring card to the line #193 had to give a fourth line to. Box 3's line overflowed by 4.7px; box 1's longest line clears by 2.8px. Same composition, same font size, same 200px card — one crossed the line and one did not, and only the one that crossed was visible to any check.

Why this was not fixed under #193

That card's ruling 1 sets the bar at "a reader cannot read a word", and none of these lines is unreadable today on the face CI renders. Ruling 2 restricts the remedy to geometry. Widening a card or re-flowing a line to buy margin is a real composition change to a published asset, and it wants its own decision rather than riding along on the repairs — especially as two of these sit in files #183 is already queued to touch.

Suggested shape

Whichever check the repo next runs over these SVGs, have it report glyph-box clearance to the enclosing card alongside the ground contrast. Both #193's five losses and this tier fall out of a single measurement, and unlike a contrast ratio it degrades gracefully — a warning threshold at, say, 8px would have caught #193's five before they shipped, and catches the next one regardless of which face the reader's browser picks.

The detector is ~25 lines of Playwright — walk every text node, find the tightest rect containing its client rect, subtract. Happy to attach it to whichever card picks this up.

Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions