MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-3497

(motir-core) `coverage-gate-globs` is a whole-tree scan MOTIR-3144's lane left behind — it globs 483 files in 0.8 s and times out at 15 s on a loaded coverage shard, twice in three days

Done
Description

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.

The two sightings

firstsecond
date2026-08-232026-08-25
pull requestmotir-core#2259motir-core#2282
run · job32628202745 · 9716682521432906725560 · 97992458441
shardVitest (1/3)Vitest (1/3)
errorTest timed out in 15000msTest timed out in 15000ms
the rest of the shard386 passed, 5635 tests passed395 passed, 5742 tests passed
the diffdocs/**, scripts/**, code commentsdesign assets, one CLAUDE.md paragraph, one edited test file

Same test, same case, same shard, zero assertion failures either time.

The measurement that names it environmental — and it is one command

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.

Why the lane's own guard does not catch it

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.

What to build

  1. Move 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.
  2. Widen 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.
  3. SWEEP for the others while you are in there and report the list, whether or not any move: the two sightings are the ones that happened to fail, not the population.

⚠️ 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.

Acceptance criteria

  • 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.
  • The sweep of step 3 is in the PR body: every 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.
  • No assertion changes. This card moves guards and widens a membership check; it does not weaken what anything checks.
  • 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.

Context refs

  • 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-3144 — the class, the lane, and the three instances that produced it. MOTIR-2815 (coverage instrumentation) · MOTIR-3067 (contention) · MOTIR-3167 (a timer bomb on the same global timeout).
  • motir-meta memories ast-guard-times-out and motir-core-ci-e2e-flake-log — both sightings, with the numbers above.