Eyes on our own build: catching what tests cannot see
How we pointed our visual regression tool at creadev.org, made every page byte-identical, and caught a bug the tests and the audit missed.
The gap between green and correct
The build passed. The SEO audit passed. The adversarial campaign passed. None of them look at the page. A test can prove a handler refuses bad input with a 400; it cannot prove the button still looks like a button. We built eyestruct for that gap: deterministic capture (look), pixel-level comparison (diff), and a committed visual memory in .eyes/ that CI can gate.
Ratify, or it did not happen
Baselines are cut in CI, not on a laptop. A local run proposes a capture with a note; the pinned-image lane reproduces it and writes the official row. The gate is browserless and reads git state plus the ledger, so an unexplained change to a committed baseline fails the build. A route earns canon only when the pinned browser reproduces it byte for byte.
The flake that hid in plain sight
One route, the projects page, refused to ratify. It captured one of two states at random, a handful of pixels apart in the header. Flags did not fix it. Isolating the region did: the theme toggle. The button sits at a fractional x, and its 1px border on a rounded corner is antialiased with run-to-run jitter. We painted the same line as an inset shadow instead, identical pixels and a deterministic raster, and all six slots went stable at 72 captures out of 72.
What the eye adds
The same memory serves three audiences. CI uses it to catch visual regressions at merge time. An adapter layer exposes the verbs where agents already work. In the instance lane, an agent can watch its own work: eyestruct serves the baked tree, spot hands back one PNG with an element map, the agent reads the pixels with its own vision, fixes what it saw, and re-spots. That is how this site got built, and how we found a bug the rest of the stack could not see.
