Every text baseline in every document was 2.4 points too high
A two-letter logo that wouldn't center led to an engine-wide correction of where text sits in its line box. The interesting part is the verification that made a global typographic change safe to ship.
Two minutes before a launch post went out, the logo mark in my own demo rendered wrong. A 36-point box with the letters "ND" in it, styled with display: flex; align-items: center, and the letters sat pinned to the top. I tried the other centering mechanism, matching line-height to the box height, the way everyone did it before flexbox. Also top-aligned. Two unrelated centering idioms, both silently doing nothing, in the standard logo-mark pattern that appears in half the invoices on the internet.
Pulling that thread found two bugs. One was ordinary. The other required moving every glyph in every document the engine has ever rendered, and this post is mostly about how you ship that kind of change without lying to yourself about what it broke.
The ordinary bug
Per CSS, a single-line flex container with a definite height sizes its flex line to the container. Ours sized the line to the tallest item. So align-items: center on a fixed-height row centered a 20-point line inside a 20-point line: a no-op that renders as top-alignment, with no error, because nothing is wrong except the answer. The fix is a max where a bare item height was. The JSX path had the identical bug in its own copy of the logic. Both got failing-first tests and that was that.
The interesting bug
The line-height idiom failing was not a flex problem. It was the engine's model of where text sits.
CSS defines a line box taller than its text: at line-height: 1.4 on a 12-point font, the line box is 16.8 points and the extra 4.8 points is leading. Every browser splits that leading evenly, half above the glyphs, half below. That split is what makes the old idiom work: set line-height equal to the box height, and the glyphs land in the vertical middle.
The engine put the baseline exactly font-size below the top of the line box. All the leading hung below the text. Every line of text the engine had ever placed sat 2.4 points too high in its line box at default settings, which is to say: slightly wrong, everywhere, in a way that no individual document made obvious. Text rendered fine. It just didn't sit where Chrome would put it, and the pre-flexbox centering idiom could never work.
The correct behavior was not in question; the CSS line box model and every browser agree. The question was whether I was allowed to change it. This is a pre-1.0 engine, and there will never be a cheaper time. But "every baseline in every document moves down" is the kind of change that either ships with real evidence or ships regressions.
What "safe" had to mean
The trap in a global visual change is that everything differs, so diffs stop being information. Every output byte-comparison fails, every screenshot changes, and a reviewer's eye glazes. The way out is to state precisely what is allowed to change, and then verify that nothing else did.
The invariant I committed to: line boxes do not move or resize. The box the text lives in stays exactly where it was; only the ink inside it shifts down by half the leading. If that holds, layout geometry, page breaks, and page counts are untouched by construction, and the change is purely about where glyphs sit within already-fixed slots.
Then I checked it from five directions:
The full test suites, 562 engine tests and 187 HTML-path tests at the time of the change, passed with the structural expectations untouched. (Both suites have grown since; the counts here are the ones that gated this change.) All 28 structural baselines in the external testkit stayed green, unregenerated. The 15-template compat corpus renders with identical page counts. That is the "boxes didn't move" half.
For the "ink moved correctly" half, I diffed the raw PDF content streams of every fixture against the pre-change engine. All six differ, as they must. The diffs were verified to be Td operators only, the PDF operator that positions text, with one fixture also moving its underline strokes, which is correct because underlines follow their baselines. Nothing else in any stream changed. A global typographic change that leaks into anything but text positioning operators is a bug wearing a costume, and this check is what would have caught it. A leak has a specific look: a border rectangle's re operands shifting means a box moved with its text, so layout was not actually untouched; a text-showing TJ array changing means glyphs or their spacing changed, and line breaks could quietly follow. Either one would mean the "only ink moves" invariant was a story rather than a fact.
The corpus rule I worked under: every document should move by the same predictable amount, and anything that moves differently is a finding, not noise. Each observed shift had to be explained by a line-height in the document's own stylesheet, or the change didn't ship.
And the visual references were regenerated only after attribution: I first confirmed the pre-change engine still passed all nine of the old references, so every one of the five visual mismatches was attributable to this change and nothing else riding along. Then I looked at the before/after images, because no amount of machinery replaces actually looking.
The gate that wasn't running
One more thing fell out, and it is the embarrassing kind of valuable. To regenerate those visual references I went to run the visual regression suite, and found it had not compiled for months. A rename elsewhere in the codebase had broken it, and because the suite lived behind a feature flag, neither cargo test nor CI ever tried to build it. It looked exactly like a passing gate. It was a dead one.
A check that isn't running is indistinguishable from a check that's passing. I have now been bitten by this shape enough times to treat it as a class: the suite is un-flagged, wired into CI as a hard gate, and configured to fail loudly when its tooling is missing rather than skip politely. If it dies again, it dies visibly.
What shipped
Half-leading went out in 0.20.0, flagged plainly in the release notes as a behavior change: every baseline moves down by (line-height − font-size) / 2, layout and page breaks unchanged, output closer to where Chrome puts text. The logo mark centers by both mechanisms. Eight failing-first tests pin the new model, and vertical-align: baseline in table cells tracks it in lockstep, because a baseline model you only half-adopt is worse than either choice.
The general lesson is the same one this engine keeps teaching me: for a change where everything is allowed to differ, the verification is the deliverable. State the invariant, prove the boxes held still, prove the ink moved only the way the model predicts, and attribute every diff before accepting it. The change itself touches two baseline computations. The evidence that it was safe is why it shipped the same week it was found. The numbers behind all of it live on the parity page, where they are measured rather than remembered.