Skip to content

The suite runner moves into the package - #53

Merged
robertblust merged 4 commits into
mainfrom
shared-suite-runner
Sep 2, 2026
Merged

The suite runner moves into the package#53
robertblust merged 4 commits into
mainfrom
shared-suite-runner

Conversation

@robertblust

Copy link
Copy Markdown
Owner

This site's verify/check.mjs now holds its SITE, its PAGES, and the checks that are genuinely its own. Everything else — the runner — comes from @robertblust/design v0.12.2.

What moved. 60 significant lines were identical in all three sites and sat outside the CHECKS object, which is the only reason the earlier consolidation missed them: the tool that measured duplication only ever looked inside that object, so "no check body exists in more than one repository" was true of the object and false of the file. They are not check bodies — they are the runner: the PAGES opt-in guards, the page loop and its result printing, and the site-wide sitemap.xml, robots.txt and favicon blocks. One of them documented its own triplication in a comment.

runSuite({ browser, SITE, BASE, PAGES, CHECKS, systemFaces }) returns a failure count. It takes a browser rather than launching one, because the package has zero dependencies and cannot import Playwright, and it returns rather than exiting, because a library that terminates its caller's process is untestable.

What this site gains. Every site ends up with the union rather than its own subset:

  • the site-identity guard — fails unless /sitemap.xml names this site. One static server on port 8000 can serve the wrong repository, and a run once reported six failures belonging to a site nobody was testing.
  • the favicon check — the favicon is the only place the brand mark exists outside a page, so no DOM check reaches it.
  • failed-request detection and a font-readiness wait on blust.ch, which never had them.

A defect worth recording, because it nearly shipped inverted. v0.12.0 built the shared runner from blust.ch's copy, on the premise that all three were identical. They were not: companygraph and guestgraph each carried a requestfailed listener and a document.fonts.ready wait that blust.ch lacked. The premise came from a measurement that found the lines common to all three and mistook the common part for the whole — so adopting the runner silently removed a check from the two sites that had it. v0.12.1 restored all three lines verbatim, making runSuite a strict superset of every site's previous runner rather than their intersection.

And the guarantee itself was described wrongly, twice. The listener catches whatever the network stack or the resource's own loader aborts: DNS failure, a refused or blocked connection, and a 404 on a stylesheet, a script or an @font-face font. It does not catch a 404 on an <img>, which completes as an ordinary response and fails later at decode. The rule is not "404 versus network failure" — it is whether the thing consuming the resource aborts the load. v0.12.2 puts that in the code comment, along with the counter-argument it has to survive: read the guarantee narrowly and the listener looks like dead weight against a localhost server.

Output is unchanged on blust.ch and gains exactly one line — ✓ /favicon.svg — on the other two. design:check is a fixed point; no card moved.

🤖 Generated with Claude Code

robertblust and others added 4 commits September 2, 2026 06:11
60 significant lines are identical in all three check.mjs files and sit
OUTSIDE the CHECKS object — the preamble with its three opt-in guards, the
page loop and its result printing, and the site-wide sitemap.xml and
robots.txt blocks. Inside CHECKS the count is 0, so the previous plan
finished that job; the tool that measured it only ever looked inside that
object, which is why 'no check body exists in more than one repository' was
true of the object and false of the file.

Two guards exist only on blust.ch and both were learned the hard way: the
site-identity guard, which fails unless /sitemap.xml names this site because
a run once reported six failures belonging to a site nobody was testing, and
the favicon check, which is the only thing that reaches the brand mark
outside a page. Sharing the runner gives both to the other two sites, and
they are expected to fail there first.

The whole runner moves rather than just the two site-wide blocks: taking
half would leave the same defect one line lower. It receives a browser
instead of launching one, since the package has no dependencies, and returns
a count instead of exiting, since a function that terminates the process
cannot be tested.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The PAGES opt-in guards, the page loop, and the site-wide sitemap/favicon/
robots checks now live in @robertblust/design's verify/suite as runSuite(),
re-pinned here at v0.12.0. check.mjs calls it instead of repeating the
runner body that used to sit outside CHECKS.
v0.12.0 built the shared verify suite runner from this site's own copy, on
the premise that the runner was identical everywhere. It was not: companygraph
and guestgraph each had a page.on("requestfailed", ...) listener and an
await ... document.fonts.ready wait that this site's copy lacked, and adopting
the shared runner silently dropped both for all three sites. v0.12.1 restores
them.

design:check remains a fixed point here (7 files, 59 fences match) and no og
card went stale. verify now attaches failed-request detection for the first
time on this site; the current suite runs clean, so no request on the live
pages is failing today. The listener was proven live by making a page request
an unreachable resource and confirming the suite named it, then restoring the
page.
Comment-only in the package: the requestfailed listener's comment described
the wrong rule. It fires for whatever the network stack or the resource's own
loader aborts — DNS failure, a refused or blocked connection, and a 404 on a
stylesheet, a script or an @font-face font. It does not fire for a 404 on an
<img>, which completes as an ordinary response and fails later at decode.

Two wrong descriptions of that listener had been written before this one, in
opposite directions, so the comment now also carries the counter-argument it
has to survive: read the guarantee narrowly and the listener looks like dead
weight against a localhost server, and deleting it on that reasoning would
take with it the only thing that catches a missing self-hosted webfont.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@robertblust
robertblust merged commit ed225a7 into main Sep 2, 2026
1 check passed
@robertblust
robertblust deleted the shared-suite-runner branch September 2, 2026 06:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant