Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-3144Done

(motir-core) The whole-tree structural guards are lint, not tests — they flake because they run inside the sharded database suite and inherit its contention

Repo: motir-core (tests/rls/*, tests/rateLimit/*, vitest.config.ts, .github/workflows/ci.yml). The THIRD instance of one class, on the third different guard — so the instance is not the problem.

The measurement that names the class

tests/rls/bare-transaction-guard.test.ts failed CI's Vitest (2/3) on PR #2145:

FAIL tests/rls/bare-transaction-guard.test.ts
Error: Hook timed out in 120000ms.

The same file, same commit, passed locally at 41 213 ms, and had passed on the same branch's previous CI run two hours earlier. It is beforeAll(scanBareTransactions, 120_000) — a whole-tree parse, not an assertion about behaviour.

41 s on a quiet box against a 120 s budget is not comfortable, it is marginal. A shard sharing a runner with seven database-heavy suites runs roughly 3× slower, so those two numbers are the same number. Prior instances, same shape:

cardguardtrigger
MOTIR-2815callSiteScan--coverage instrumentation multiplied the parse cost
MOTIR-3067storeDeadlinecontention from a sibling session on the same box
(this)bareTransactionScancontention on a CI shard

The structural cause, which no per-guard fix reaches

At least ten of these exist — seven in tests/rls/ alone (callSiteScan, bareTransactionScan, ratchetScan, systemContextScan, singletonReadScan, testCallSiteScan, testSingletonStatementScan), plus rateLimit/one-counter-guard, rateLimit/storeDeadline, permissions/roleAssignment.

Every one of them reads the filesystem and needs no database — they are lint, in the shape of tests. But they execute inside the sharded Vitest run, so they:

  • compete for CPU with database suites that are themselves the slow part;
  • inherit a testTimeout sized for a database call, not a 3 000-file parse;
  • get re-paid per shard, because each shard that contains one runs its own scan.

That is why fixing them one at a time keeps not working: each fix lowers one guard's cost, and the next guard inherits the same environment.

What to build, in this order

  1. Move the structural guards into their OWN job, beside Lint + Prettier. They stop competing with database suites, their duration becomes predictable, and the total gets faster — one scan pass rather than one per shard that happens to hold one. This is the fix that removes the class.
  2. Memoise each scan per ROOT. ⚠️ Keyed by root, not a single unkeyed cache: the fixture tests deliberately scan a different tree, and one shared cache would hand them the real repository's answer and pass vacuously (the trap MOTIR-2815 already hit).
  3. Use the slice-based comment stripper. Measured on the sibling: out += src[i] over 28 MB = 2 187 ms; regex-hop + indexOf + slice + join = 169 ms, byte-identical across 2 966 files. Verify equality against the naive version once in a throwaway script — the fast path has real edge cases (a // inside a string literal).

⚠️ Do NOT simply raise the budget. That is the move already made for two of the three instances; it lowers probability and leaves the class. A budget is only honest once the guard is out of contention and its cost is bounded.

Acceptance criteria

  • Every filesystem-scanning guard runs in a dedicated CI job, not inside the sharded Vitest run — enumerated in the card, so a guard left behind is visible rather than assumed.
  • That job's wall-clock is reported in the card, before and after, measured rather than estimated.
  • Each scan is memoised per ROOT, and a test proves a fixture-tree scan still gets the FIXTURE's answer — the vacuous-pass trap, asserted rather than avoided by care.
  • The comment stripper's fast path is proved byte-identical to the naive one over the whole tree, and that check is recorded in the PR body with its numbers.
  • No guard's assertions change. This card moves and speeds them; it does not weaken what they check.
  • pnpm test and the coverage lane are both green, and the guards' new job is green — all three, because the class has previously hidden in exactly the lane nobody ran.

Context refs

  • tests/rls/bareTransactionScan.ts · tests/rls/bare-transaction-guard.test.ts — the failing instance, and a scan re-derived from four separate cases in one file
  • tests/rls/callSiteScan.ts · tests/rls/ratchetScan.ts · tests/rls/systemContextScan.ts · tests/rls/singletonReadScan.ts · tests/rls/testCallSiteScan.ts · tests/rls/testSingletonStatementScan.ts
  • tests/rateLimit/one-counter-guard.test.ts · tests/rateLimit/storeDeadline.test.ts · tests/permissions/roleAssignment.test.ts
  • vitest.config.ts — the 15 s testTimeout these budgets are measured against
  • .github/workflows/ci.yml — the Lint + Prettier job this should sit beside
  • MOTIR-2815 (coverage instance) · MOTIR-3067 (contention instance)
  • The failing job: PR #2145, run 32276806012, Vitest (2/3)
  • motir-meta memory ast-guard-times-out — all three instances and the measured fixes