Repo · motir-core (tests/coverage-gate-globs.test.ts, tests/helpers/structuralGuardLane.ts, tests/ci-structural-guards-lane.test.ts).
MOTIR-3144 diagnosed the class — whole-tree structural guards are lint, not tests; they flake because they run inside the sharded database suite and inherit its contention — and shipped the Structural guards lane that removed it for ten guards. tests/coverage-gate-globs.test.ts is the same class and is not in the lane. It has flaked twice in three days since.
| first | second | |
|---|---|---|
| date | 2026-08-23 | 2026-08-25 |
| pull request | motir-core#2259 | motir-core#2282 |
| run · job | 32628202745 · 97166825214 | 32906725560 · 97992458441 |
| shard | Vitest (1/3) | Vitest (1/3) |
| error | Test timed out in 15000ms | Test timed out in 15000ms |
| the rest of the shard | 386 passed, 5635 tests passed | 395 passed, 5742 tests passed |
| the diff | docs/**, scripts/**, code comments | design assets, one CLAUDE.md paragraph, one edited test file |
Same test, same case, same shard, zero assertion failures either time.
The whole file pays ONE memoised glob (reportableFiles() in tests/helpers/coverageGate.ts), and the first it is what pays it:
npx tsx -e "const {reportableFiles}=await import(process.cwd()+'/tests/helpers/coverageGate.ts');
const t=Date.now();const f=await reportableFiles();console.log(f.length,Date.now()-t)"
483 files in 785 ms on the branch; 483 files in 986 ms on origin/main. Same input, same cost — so the second sighting's diff did not touch the scan, and neither did the first: coverage.include reaches no path either diff edited. A 0.8 s scan blowing a 15 s budget is a contention multiplier over 19x, which is inside the range MOTIR-3144's own fourth instance measured.
Two variables the second sighting rules out that the first could not: no test file was added or removed, so shard membership was identical to main's; and every other check on that commit was green, E2E shards included.
tests/ci-structural-guards-lane.test.ts fails when a guard imports a scanner helper and is in neither the lane nor DATABASE_BOUND_GUARDS. coverage-gate-globs imports tests/helpers/coverageGate.ts, which is not on that list — it globs with tinyglobby rather than parsing with the TypeScript compiler API. So the membership test keys on the IMPLEMENTATION a guard happens to use, not on the property that makes it flake: doing whole-tree filesystem work under a 15 s budget on a coverage-instrumented shard. That is the same shape as the class itself — a check that enumerates the instances it knows about.
tests/coverage-gate-globs.test.ts into the Structural guards lane (vitest.guards.config.ts via tests/helpers/structuralGuardLane.ts), and exclude it from the root config exactly as the ten already there are. It needs no database and no --coverage; it reads vitest.config.ts and the filesystem.ci-structural-guards-lane's membership test from the IMPORT to the PROPERTY. A guard that reaches the filesystem for a whole-tree answer belongs in the lane whichever helper it uses — tinyglobby, fast-glob, readdirSync, or the compiler API. Enumerate the entry points rather than the one scanner family, and state in the test why each is a carrier.⚠️ Do NOT raise the budget. MOTIR-3144 settled that: a budget derived from a quiet-box measurement cannot cover a multiplier that has been observed above 14x, and raising it lowers the probability while leaving the class.
tests/coverage-gate-globs.test.ts runs in the Structural guards job and not in the sharded Vitest run — asserted by the lane's own membership test, not by inspection.pnpm test:guards is green and its wall-clock is reported in the PR body, before and after.ci-structural-guards-lane's membership test fails for a guard that does whole-tree filesystem work through any entry point, demonstrated with a synthetic case rather than asserted — the same demonstrated, not assumed bar the loading-boundary guard meets.tests/** file that reaches the filesystem for a whole-tree answer, with its lane and a verdict per file. A file left where it is carries a reason.pnpm test, the coverage lane and the guards job are all green — all three, because this class has twice hidden in exactly the lane nobody re-read.tests/coverage-gate-globs.test.ts · tests/helpers/coverageGate.ts — the guard and its memoised glob.tests/helpers/structuralGuardLane.ts · vitest.guards.config.ts · tests/ci-structural-guards-lane.test.ts — the lane, its config, and the membership test to widen.vitest.config.ts — the 15 s testTimeout the budget is measured against, and the coverage.include set the guard reads.motir-meta memories ast-guard-times-out and motir-core-ci-e2e-flake-log — both sightings, with the numbers above.