(motir-core) Story gate — two workers do not double-fire a tick, the coverage floor, and the totality guards a percentage cannot see
The story's motir-core vitest gate: a coverage floor, the seams between the three code subtasks, and the guarantees a coverage percentage cannot see. Real Postgres, not mocks.
It runs AFTER the story's code subtasks merge, because it measures their real, merged surface. It is a gate resolved at run time, not a list of cases enumerated now — "already covered by the per-subtask floor" is the expected normal for much of it, not a redundancy to pre-subtract.
(1) Coverage floor
Run coverage over the story's changed surface — the scheduler, the repository method, the defineJob / EngineJobDefinition option, the 14 declarations — and wherever a file is below the project's per-file floor (≥90% branch/fn/line, CLAUDE.md § coverage), write the missing unit and branch tests to reach it.
(2) Integration seams
The joins the units mock:
- Scheduler → repository → claim → ledger. Drive a real tick against a real Postgres, then a real worker claim, and assert the
job_runrow that comes out — includingevent_name = 'scheduled.<jobId>', which is the field three separate consumers read and no unit test of the scheduler alone can prove. - A scheduled run that THROWS reaches the DLQ. Exhaust the attempt budget on a scheduled row and assert the
job_run_dlqrow and thefailedledger row, via the worker's terminal-failure hook.lib/jobs/engine/ledger.tsexplains at length why this write is easy to appear to test and not have — an in-process harness ran the catch synchronously and made the original Inngest bug look fixed when it was not (PRODECT_FINDINGS #39). Drive it through the worker's settle path, not around it. - The declared
catchUpreaches the tick. Assert the disposition each of the 14 declares produces the row set the scheduler writes — the declaration and the reader are two cards, and this is the seam between them.
(3) Architecture and totality guards
The things a percentage cannot see:
- TWO WORKERS DO NOT DOUBLE-FIRE A TICK. The story's headline criterion. Two
JobWorkers, or two concurrent ticks, against one warm real-Postgres pool, both scheduling the same fire — exactly onejob_queuerow and exactly onejob_run. Sequential calls do not test this, for the reasonclaimDueRuns' own header gives: the race needs genuine concurrency, and a serial test passes against a broken implementation. - A routed cron job does not also run on Inngest.
defineJob's guard returns{ skipped: 'routed-to-postgres-engine' }; assert it fires for a CRON-triggered invocation specifically. The switch's existing tests cover the event path; a cron job reaches the handler by a different trigger and the negative direction deserves its own assertion. - Registry totality. Every id in
engineScheduledJobs()carries acatchUp, and the id set is READ from the registry rather than transcribed — so a fifteenth cron job added later fails this suite instead of shipping with no policy. - Schedule constants unchanged. Assert the 14 cron expressions against their exported constants, so a cutover cannot quietly re-time a sweep.
jobScheduleHealthServicestill judges a migrated job correctly. Seed a scheduled ledger row via the ENGINE path and assertcheck(now)reads it as healthy — the probe is unchanged and this proves it did not need to change.
Scope boundary
One repo, one suite, one PR. This gate is motir-core's; the story has no second repo.
Does NOT re-derive what the per-subtask unit tests already cover, and does NOT assert anything only a deployment can show — no production ledger, no live cadence. Those belong to the production cutover task under the epic.
Acceptance criteria
- Every file this story changed meets the ≥90% per-file floor, or the gap is named with the reason the line is unreachable.
- The double-fire assertion runs concurrently against a real Postgres and fails against a deliberately-broken check-then-insert — verify by breaking it locally once; a concurrency test that passes both ways is not a test.
- A scheduled run's DLQ path is asserted through the worker's settle path, with the ledger row and the dead-letter row both present.
- The
catchUpseam is asserted for at least one job of each declared disposition. - The registry-totality and schedule-constant guards read the registry, never a hard-coded list of 14.
- The suite runs in CI's existing vitest lane with no new service — real Postgres is already how
tests/jobs/engine-*.test.tsruns.
Context refs
tests/jobs/engine-worker.test.ts·tests/jobs/engine-ledger.test.ts·tests/jobs/engine-schema.test.ts·tests/jobs/engine-story-gate.test.ts— the shape MOTIR-3414's own gate took, and the suites to extendtests/jobs/schedule-health.test.ts— the registry-import precedent and the probe's own testslib/jobs/engine/ledger.ts— the PRODECT_FINDINGS #39 warning about a test harness that lieslib/repositories/jobQueueRepository.ts—claimDueRuns' note that a serial test cannot see the defectCLAUDE.md§ coverage — the per-file floor