Files
Claude 8f790e5d7f fix(ci): delete the root test that read site/ instead of patching around it
#219 was a site-only PR that deleted a file a ROOT test read off disk. The
`changes` filter set root=false, the root jobs were SKIPPED, the PR merged GREEN
and main broke on an ENOENT — a skipped job and a passing job are the same tick
in the checks list, so nothing announced it.

That was patched twice before anyone asked whether the test should exist. It
should not. What it asserted:

    expect(hero).toMatch(/\bLANGUAGES\b[^;]*from ["']@\/lib\/linters["']/s);
    expect(heroCode).not.toMatch(/Any language/);

Both are properties of the SITE — an import line and a piece of copy — checked by
regexing the SOURCE TEXT of two site files from a test about the engine's linter
registry. Three defects, only the third visible: it asserts the shape of the text
rather than the value, so a rename or a reformat breaks it; a substring search
cannot tell an assertion from a comment discussing one, and it had already fired
on exactly that (its own comment says so); and it made root depend on site, which
is the dependency that produced the green-merge-red-main above.

Deleted. The property moves to where it belongs and gets stronger on the way:
site/src/lib/linters.browser.test.ts now RECOMPUTES the derivation from the
engine and compares values —

    expect(LINTER_NAMES).toEqual(BUILTIN_LINTERS.map((l) => LINTER_LABELS[l] ?? l));
    expect(LANGUAGES).toEqual(LANGUAGE_ORDER.filter((lang) => …));

so a hand-typed array is no longer forbidden, it is made HARMLESS: it must equal
what the engine implies and goes red the moment BUILTIN_LINTERS moves under it.
That test runs in the `site` job, which is gated on site changes — the job that
would have run for #219.

With the read gone, the filter's own invariant is true again, and now it is
CHECKED rather than asserted in a comment: src/ci-path-filter.test.ts fails if
any root test reads site/ off disk. Mutation-proven — reinstating one read fails
exactly that test.

⚠️ Two of my own errors on the way here, both mine and both worth the record.
The first fix I wrote for this declared the cross-read in ci.yml instead of
removing it — treating the symptom a third time. The second was in the guard
itself: `grep -rl` exits 1 when it finds nothing and execFileSync throws on a
non-zero exit, so the check went RED precisely when the property HELD. It now
reads the exit code instead of letting it decide.

Gates: npm run check 18/18. npm run coverage 3959 passed, 0 failed; the 99.94%
statement gate is src/mock-model.ts:147,339,374, untouched here and green on CI
(25 tests skip locally and never reach those lines).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 22:12:17 +00:00
..