Our Test Corpus Was All Imports, So Authoring Was Broken for Months
TLDR
We validated a geometry analysis pipeline against a corpus of imported SVG files and shipped it green. Content authored inside the editor went through the same pipeline and produced wrong answers for months, because imported geometry is flattened and authored geometry carries live transforms. If your feature has two producers, a test corpus drawn from one of them proves half the feature.
The assumption that seemed reasonable
The pipeline classifies SVG elements into wires and components, discovers connection ports, and builds electrical nets. It was developed against real files: schematics exported from other tools, PDFs converted to vectors, hand-edited SVGs.
The assumption: the pipeline consumes the DOM, and the DOM is the DOM. Whether an element arrived by file import or by a user placing it from a palette, it is the same node type in the same tree. One corpus should cover both.
Every pipeline change was regression-checked against the corpus. The corpus stayed green for months. Nobody drew a circuit by hand and then ran the checker on it, because drawing by hand was slower than dropping a test file, and the corpus was right there.
When it failed
A live browser session finally did the obvious thing: place two components from the palette, wire them pin to pin, run the design check.
The checker reported both components fully disconnected. Zero of two pins each. The wire was visibly attached to both pins on screen, and the wire even carried connection metadata from the drawing tool. The report was not degraded. It was maximally wrong, delivered with a straight face.
What was actually wrong
Imported files are flattened. Coordinates are baked into path data and attribute values during import, transforms are de-nested, and every number is in document space.
Authored symbols are not flattened. A palette placement creates a group with local geometry and a translate(x, y) transform, because that is what makes moving and rotating cheap. The group's transform is the position.
The pipeline measured element bounds with getBBox(), which returns local coordinates and ignores transforms. On the flattened corpus, local space equals document space, so getBBox() was always right. On an authored symbol, getBBox() returned a box centered near the origin while the wire endpoints being matched against it sat hundreds of units away. The port matcher compared the two and found nothing, every time.
The corpus could not catch this by construction. Flattening is exactly the operation that erases the difference the bug depends on.
What got deleted
The bbox-only port matcher went away, along with a regex that parsed translate(x, y) out of transform attribute strings in one other code path. The regex deserves its own sentence: it worked until the day an element carried rotate(...) translate(...), because string-parsing one transform function out of a chain is just the same bug wearing a different hat.
What replaced it
A matrix-walk helper projects any element's local geometry into document space by consolidating the ancestor transform chain, stopping below the camera group. The classifier projects symbol bounds through it. The port matcher projects pin marker positions through it and matches wire endpoints against actual pins with a small tolerance, recording which pin matched.
And the test loop changed shape: the editor now gets exercised through the browser with scripted pointer input, place, wire, check, assert on the report. Authoring is a producer, so authoring is in the loop.
The audit that followed
Once one producer-specific bug exists, the honest move is to assume its siblings exist too. We swept every consumer of element geometry for the same local-versus-document confusion and found two more.
The unconnected-pin badge logic already projected pins correctly, but it only ran when the pipeline ran, and the pipeline only ran on import and undo. So the badges were coordinate-correct and time-stale: accurate for imported files, frozen for authored edits. The fix was scheduling, not math. The analysis pass now triggers off the history push, so any completed edit refreshes it.
The marquee selector had its own private matrix walk that was correct, which proved the projection knowledge existed in the codebase all along. It just lived in one feature instead of being a shared primitive the pipeline could use. Extracting it into a single helper turned a lurking class of bugs into one function with one owner.
The generalizable lesson
Count your producers. A pipeline that consumes "the document" almost always has more than one thing writing that document: the importer, the authoring tools, undo restore, paste, collaborative sync. Each producer leaves different fingerprints. Flattened versus live transforms. Normalized versus raw attribute forms. Ids present versus absent.
Your test corpus has a producer distribution, and whatever producer is missing from it is the one your users exercise first. The corpus did not fail us. We failed to notice what the corpus was made of.