(motir-core) Story gate — vitest coverage floor, the emit-to-run seams, and the totality guards a percentage cannot see
The story's per-repo vitest gate. It runs AFTER every code subtask of this story has merged, against real Postgres, and does three things — none of which is a static list of cases written now.
1. Coverage floor
Run coverage over this story's changed surface and, wherever a file is below the project's per-file floor (≥90% branch / function / line — motir-core/CLAUDE.md § coverage), write the missing tests to reach it. Each subtask ships its own units; this tops up the seams BETWEEN them.
⚠️ Sort the report before writing a single bullet. A coverage zero measures execution and says nothing about reachability, so nobody tested this and nothing can test this produce the same cell. Split the uncovered arms into defensive (a ?? null, an unreachable default:, a guard on a value its producer cannot emit) and rule-bearing (a filter, an early return, a status branch), and read each verdict off the PRODUCER of the value the arm tests, not off the arm. Where an arm is genuinely dead, the criterion is a test asserting the INVARIANT that makes it dead, plus an ignore directive citing that test by name — never an ignore directive alone, which moves the number and hides the gap.
2. The emit→run seam, end to end
The units mock the boundary; this drives it. For one fast-lane consumer, in one test, against real Postgres: emit through sendEvent → the dispatcher writes job_event + job_queue → the worker's claim path picks it up → the handler runs → job_run carries the ledger row /settings/workspace/jobs reads. Assert the DTO the operator surface consumes, not the table — a key drift between the writer and the reader is exactly what per-subtask units cannot see, because each side mocks the other.
Do the same for the idempotency seam: two events, one key, one delivery, read back through the same DTO.
3. The guards a percentage cannot see
- Totality of the routing switch over the WHOLE registry. For every registered non-cron job, routing it moves it and only it: with its id in the set,
dispatchEventToEngineenqueues it; with the id absent, it does not. And the split-subscriber invariant, which is what makes a partial cutover safe —hasInngestSubscribersstaystruefor an event while ANY of its subscribers is unrouted, and turnsfalseonly when the last one moves. Derive the job list from the registry, never from a hand-written array. - The import boundaries, as tree-level assertions. Nothing outside
lib/jobs/**+scripts/worker.tsreaches the engine internals (JOB_ENGINE_RESTRICTION) or@/lib/jobs/client(the boundary this story widened). A lint rule is enforcement; this is the assertion that the rule still has the shape the story gave it. - Tenancy. The dispatcher writes
job_eventandjob_queuethroughwithSystemContext. Assert the rows carry the emitting event'sworkspace_id— including the deliberatenullfor a cross-workspaceemail.send— and that they are subject to RLS rather than written at the tenant root. Fixtures useadminDb.
Scope boundary
motir-core only — this story ships in one repo, so it has one gate card and it does not straddle.
Asserts only the ASSEMBLED surface of its merged dependencies. Nothing here tests the scheduled-job cutover, the supervisors, or any behaviour whose code has not landed. Nothing here measures latency: a CI runner has no production load and no scheduler, so a timer around a function call would pass forever and fail for unrelated reasons — the latency reading is the re-measurement task's, taken from production. tests/jobs/fast-lane-latency-budget.test.ts already draws this line for the same budget and says why; do not blur it.
Acceptance criteria
- Every file this story changed meets the per-file coverage floor, or carries an ignore directive naming the invariant test that proves the arm dead.
- The emit→run seam test drives a real
sendEventto a realjob_runrow against real Postgres, and asserts through the DTO the operator surface reads. - The idempotency seam test proves one delivery for two same-key events, read back through that same DTO.
- The routing-totality guard iterates the registry rather than a literal list, and FAILS if a job is added whose event cannot be routed.
- The split-subscriber invariant is asserted in both directions on an event with more than one subscriber.
- The two import boundaries are asserted over the tree.
- The tenancy assertions cover both a workspace-scoped event and the
null-workspaceemail.sendcase. - The suite passes with no
retriesconfigured — a retry here would hide exactly the ordering flakiness this gate exists to expose.
Context refs
tests/jobs/engine-dispatcher.test.ts·engine-worker.test.ts·engine-ledger.test.ts·engine-story-gate.test.ts— the shipped engine suites this composes with, and the shape MOTIR-3426 established for a gate cardtests/jobs/rls.test.ts— the tenancy assertions to extendtests/helpers/adminDb.ts— the owner client fixtures uselib/jobs/engine/dispatcher.ts·lib/jobs/engine/registry.ts— the registry the guards must derive fromlib/services/jobRunsService.ts·lib/dto/jobs.ts— the consumer DTO the seam tests assert throughtests/jobs/fast-lane-latency-budget.test.ts— the precedent for what this suite must NOT claim to measure