Coordinate Spaces and Page Snap: A Three-Part Series on Silent Math Bugs in a PDF Editor
TLDR: This was originally a single 2,600-word post about three silent math bugs we found while polishing the PDF processor's UI. None of them crashed. None of them failed tests. All three quietly produced wrong output. We've split it into a four-part series so each invariant gets the focused treatment it deserves.
Repo: tools/pdf-processor
A working tool can hide a lot of incorrect math.
Our browser-based PDF processor had been in flight for weeks when I sat down to add UI polish: alignment buttons, a zoom control, scroll sync between the visual diff panes. Three things. Half a day's work.
By the end of the day I had retrofitted three foundational invariants into the codebase. Each one was a piece of math that had been silently wrong, surviving every test because nothing crashed.
This series breaks down each one. They look unrelated on the surface. They turn out to be the same problem underneath.
The series
Part 1: Why coordinate spaces are not optional in PDF extraction When an SDK gives you positions in one space and dimensions in another, mixing them in a single arithmetic expression breaks four downstream heuristics at once. The fix is small but the lesson has teeth.
Part 2: Why semantic and spatial layouts can't share a ruler A PDF page is spatial: roughly 1100 pixels every page. An HTML page is semantic: 200 pixels or 2500 pixels depending on content. Syncing them with within-page math is fiction. IntersectionObserver fixes it in thirty lines.
Part 3: Three editable surfaces, one source of truth The PDF processor had three DOM surfaces showing the same HTML, each believing it was canonical. They disagreed. We retrofitted a controlled-input pattern with a shared guard flag and a skip-source rule.
Part 4: The pattern under all three The three bugs above look unrelated. They are the same bug. Two things were treated as equivalent that were not. The form of equivalence was different each time. Here's the discipline that catches the next one.
The whole rebuild is open source. If you spot a fourth invariant we missed, the issue tracker is open.