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-3486

(motir-core) Story gate — a supervisor RESUMES after a real worker restart, the debounce coalesces a burst, and the ledger contract and admission cap are untouched

Done
Description

The story's per-repo COVERAGE + INTEGRATION gate, run against real Postgres after the three feature cards have merged. It measures their REAL merged coverage, tops up the seams between them, and asserts the guarantees a percentage cannot see.

1 · Coverage floor

Run coverage over the surface this story changed — lib/jobs/indexFleetSteps.ts, lib/jobs/definitions/ciRunnerFleet.ts, lib/jobs/engine/dispatcher.ts, lib/jobs/engine/registry.ts, the touched parts of codeGraphIndexDispatchService and ciRunnerBootService — and write whatever unit and branch tests are needed to reach motir-core/CLAUDE.md's per-file floor of ≥90% branch / function / line. "Already covered by the per-subtask floor" is the EXPECTED normal here, not a reason the card has nothing to do: the gate's job is the seams between the three cards, not their interiors.

⚠️ Sort the report before writing a bullet. These files are full of defensive arms — catch blocks around provider reads, ?? null on optional session fields, the MAX_CONSECUTIVE_READ_FAILURES limb — which are uncovered because they are unreachable at least as often as because nobody wrote them. For each gap say what would have to be true for the arm to FIRE, reading the code that BUILDS the value rather than the arm itself; where an arm is genuinely dead, the criterion is a test asserting the INVARIANT plus an ignore directive citing that test by name, never a fixture nobody can build and never a dropped bullet.

2 · The seams between the three cards

These are the writer→consumer pairs the units mock, driven end-to-end against real Postgres:

  • debounce → worker. A same-key burst leaves ONE pending row; the worker claims it and the handler sees the LAST event's payload — not the first. This is the pair most likely to drift, because the debounce card asserts the row and the collapse cards assert the handler, and nothing today asserts that the row the worker picks up carries what the last push said.
  • collapse → ledger. A supervised run driven to completion through the real worker writes ONE job_run per repo, succeeded, with ONE output.repoRef; a run whose container did not exit 0 writes a FAILED row carrying the named exit class.
  • collapse → job_step. The step rows a completed supervision writes are a small CONSTANT, and the number does not grow with the poll count. Assert the number, not merely that it is "small" — this is the property the whole collapse buys, and a regression here is silent.
  • worker restart → the same container. THE STORY'S OWN CRITERION, and it must actually restart: drive a supervision to mid-flight, kill the worker, bring a second one up, and assert it resumes watching the SAME container handle rather than booting another. MOTIR-3426 built the engine's crash-resume guards — extend that lane rather than standing up a second harness beside it.

3 · The guards a percentage cannot see

  • The admission cap and the fleet limits are UNTOUCHED. codeGraphIndexAdmissionService and lib/ciFleet/limits.ts are named in MOTIR-3417's criteria as forbidden ground because a regression there costs money. Assert the budgets by value.
  • Every time budget survives the collapse by valueINDEX_FLEET_TIME_BUDGETS, INDEX_ADMISSION_BUDGETS, FLEET_TIME_BUDGETS, indexPollWaitMs, indexAdmissionWaitMs, pollWaitMs — read from the shipped constants, so a collapse that quietly changed a cadence fails here.
  • TOTALITY of the debounce key resolver. An expression it cannot resolve throws at registration; there is no arm that silently returns null and merges unrelated repos into one bucket. codeGraphRefresh's own header names that failure explicitly.
  • The three supervisor jobs are still reachable on BOTH lanes. With their ids absent from the routing set they run on Inngest exactly as today; with the ids present they enqueue job_queue rows. The switch's default-to-Inngest safety property has a test in MOTIR-3414's gate for the same reason.
  • ONE composition is structural, not stylistic. A guard asserting that a poll loop appears in exactly one place per fleet — the thing this story deletes cannot grow back by copy-paste, and only a test that reads the tree can say so.

Scope boundary

ENDS at: this repo's vitest suite green, at the floor, with the seams and guards above.

One repo, one suite, one PR. Everything this story touches is motir-core; there is no second gate card.

Does NOT assert anything about the E2E flowthe story E2E drives the browser-visible path and is a sibling, not a dependency.

Does NOT re-derive coverage the three feature cards already ship. Each of them owes its own units; this card tops up what falls between them.

Does NOT assert a claim about PRODUCTION. The ids are not in MOTIR_POSTGRES_JOB_IDS when this lands — that is the operator task, after the merge.

Acceptance criteria

  • Every file this story changed is at or above the ≥90% per-file branch / function / line floor, measured on the merged result rather than per branch.
  • Each of the four seams in §2 has a test against REAL Postgres, and the worker-restart one kills and restarts an actual worker process rather than simulating one.
  • The job_step count for a completed supervision is asserted as an exact number, and the test proves it is independent of poll count by running the same supervision at two different poll budgets.
  • Every guard in §3 is a test that FAILS when the property is broken — verified by breaking each one locally once and watching it go red, not by assuming it would.
  • Any coverage gap left open is a DEAD arm with a named invariant test and an ignore directive citing it, and the card lists them; nothing is closed with an unexplained ignore.
  • The suite runs in the repo's normal vitest lane with no new harness, and adds no new external service.

Context refs

  • motir-core/CLAUDE.md § coverage — the ≥90% per-file floor this measures against
  • tests/jobs/engine-worker.test.ts · tests/jobs/engine-step-shim.test.ts · tests/jobs/engine-story-gate.test.ts — the engine's existing gate lane and its crash-resume shape
  • tests/jobs/engine-dispatcher.test.ts — the fan-out and idempotency tests the debounce sits beside
  • tests/jobs/debounce-burst.test.ts — the Inngest-side coalescing guard, whose engine twin belongs here
  • tests/helpers/perWorkerDb.ts — the real-Postgres harness
  • tests/ciFleet/ — the CI fleet's existing suites, including the admission-wake caller of runIntent
  • lib/services/codeGraphIndexAdmissionService.ts · lib/ciFleet/limits.ts — the untouchable budgets to assert by value