The build check that passed while the editor broke
Four internal registries agreed. Twelve published pages still used a value Keystatic rejected.
5 minute read
lordtime

One of my build checks compared the Keystatic schema, Astro renderer, component registry and editor catalogue. All four agreed. Twelve published pages still contained a value the editor rejected.
The public site rendered those pages correctly. Keystatic refused to open them. The check proved that four abstractions matched one another, but it never inspected the content they governed.
I fixed the missing option, then changed the check to validate every site’s content against every select field. I also put the old defect back temporarily and watched the new check fail before trusting its passing result.
The failure
Tone on this site is a shared list of six surfaces — default, muted, accent, contrast, gradient and plate — defined once and used by every block that paints a background. Except that two blocks didn’t use the shared list. They’d been written with their own five-item lists, before plate existed, and nobody updated them when it was added.
Twelve pages used tone="plate" on one of those two blocks. The site rendered them perfectly: the renderer looks the tone up in a map, the map has all six, the CSS class exists. Every page built, every check passed, the pages looked right.
Then someone opened one in the editor and got this:
“Field validation failed: body: Unexpected error: Error: tone: Must be a valid option”
The published content used an option the schema did not allow. The site rendered correctly while Keystatic refused to open the page.
The missing option was a one-line fix. Both blocks now draw from the shared list, so that particular mismatch cannot recur. The more important change was to check:block-registry: after comparing the four registrations, it now reads every site’s MDX and verifies that values such as tone="plate" exist in the corresponding select field.
Other checks, with narrower claims
The same repository has checks for colour tokens, contrast pairs and block registration. Each is useful because its scope is explicit.
npm run check:token-purity scans governed component and style source for literal colours outside src/styles/tokens.css. Without enforcement, a one-off colour is easy to add before a deadline. Repeated often enough, those exceptions make dark mode and brand changes harder to reason about.
check:design-tokens evaluates the foreground and background token pairs defined by every theme preset and colour scheme. It fails when a governed pair misses its configured WCAG AA threshold. That calculation is suitable for automation because the colours, text role and threshold are known.
It does not prove that a rendered page is accessible. Text size, gradients, images, opacity, component state, focus order, alternative text, form labels and keyboard behaviour need broader automated and human evaluation.
The block registry check has a similarly limited job. It confirms that a Keystatic block has an Astro renderer and editor catalogue entry under the same name, then checks select values used by the content. It does not judge whether the block is useful or whether its copy is good.
The public site ships no client framework
The site is built with Astro. Keystatic uses React in the CMS build, but React is absent from the public output. Navigation, the table of contents and the theme toggle use small page-scoped scripts written for those behaviours.
This trades framework convenience for a smaller public runtime and scripts with explicit scope. It suits a site made mostly of text and images. An application with substantial client state should make a different decision.
When a check isn’t worth writing
Checks cost maintenance. A check that fails for the wrong reason gets disabled, and a disabled check is worse than no check, because it still looks like coverage in the list. So a rule earns a script only when three things are true: it’s objective, it gets violated by accident rather than by decision and it’s cheap to run.
I do not write checks for whether the copy is good, an illustration works, a page is the right length or a heading is honest. Those questions matter, but a script cannot settle them. Automating a weak proxy would add noise while making the build appear more comprehensive than it is.
Sources
- Understanding SC 1.4.3: Contrast (Minimum) — W3C — The AA thresholds the token check enforces. Checked 20 August 2026.
- Content collections — Astro docs — The schema layer the content is validated against at build time. Checked 20 August 2026.
Want a build somebody else can still work on in three years?
Tell us what the site has to do. We'll tell you what it doesn't need — and you keep the repository either way.