11.4.9 Story vitest gate — coverage floor, the schema→emitter→document→page seams, and the contract guards the spec work owes
Repo: motir-core. One PR. The story-level vitest gate — the mandatory per-repo coverage + integration + architecture card that runs AFTER this story's feature subtasks merge, because it measures their real, merged result. Same shape as 11.1.5 and 11.2.11.
This is not a list of cases written at plan time, and "already covered by the per-subtask floor" is the expected normal it resolves at run time, not a redundancy to subtract in advance. Three jobs:
1. Coverage floor
Run coverage over this story's changed surface — the shared schema layer, the operation registry and emitter, the operation declarations, the spec route and the docs pages — and wherever it sits below the project's ≥90% per-file branch/function/line gate, write the missing tests to reach it. Each subtask ships its own units as the floor; this tops up the seams between them, which is where no single subtask's tests reach. Where a file is gated on functions+lines instead of branches, the reason is written beside it.
2. Integration seams — one card's REAL output through the next card's REAL consumer
Four cards compose into one pipeline and their units mock each other's edges. Cover the real compositions:
- Shared schemas → emitted document. The envelopes, error body, rate-limit headers and security scheme declared by 11.4.3 appear as real components in the document 11.4.4 emits, referenced by operations rather than inlined per operation.
- Emitter → the served route. The bytes the route returns parse back into a document identical to what the emitter produced — not a document assembled a second way for the test.
- Document → the reference page. The rendered operation set equals the registry's operation set, driven from the real emitter output, so an operation cannot exist in the document and be missing from the page (or vice versa).
- Registry → route reality. Every operation's declared scope equals the scope its route file declares, read from the real tree via
declaredScopeByMethod(). - Guide → API. The endpoints, parameters and headers 11.4.8's getting-started page names resolve to real routes and real headers.
3. Architecture / contract guards — what a coverage percentage cannot see
- The document is DETERMINISTIC: emitting twice from the same registry produces byte-identical output. A generator whose key order wanders makes every diff unreviewable and every "did the contract change?" question unanswerable.
- The spec route's exemption stays bounded — exactly one exempted path, and that file authenticates nothing, opens no transaction and reads no database.
- The reference page does not fetch its own public URL — it reads the emitter directly; a self-fetch is a runtime dependency on the app being up to render the app.
- The emitter is request-independent: it takes no
Request, no session and no workspace, so the document cannot vary per caller. A per-caller contract is not a contract. - No cuid leaks into the document's examples or component schemas — the same identifier rule
tests/api/v1/story-gate.test.tsalready asserts for response bodies, applied to the published description of them.
Real Postgres where a seam needs it, no mocked database.
Scope BOUNDARY
One repo, one suite, one PR — nothing in this story touches another repo. It asserts only the assembled surface of its DONE blockers and pulls no coverage forward for 11.5 or 11.6, which ship their own. It is not the route↔spec drift guard — 11.4.6 owns those three drifts and this card does not re-derive them — and it is not the browser E2E. It changes no production code; a defect it finds is fixed here only if this story caused it, otherwise it is logged as a bug.
Acceptance criteria
- Every file this story added or changed meets the ≥90% per-file floor in
vitest.config.ts, with a written reason beside any file gated differently. No existing gate entry is weakened. - Each integration seam above has a test driving REAL components, with no mock standing in for another subtask's output.
- Emitting the document twice yields byte-identical output, asserted.
- The exemption bound, the no-self-fetch rule, the request-independence of the emitter and the no-cuid rule each fail when deliberately violated in the test.
- Tests use real Postgres where the seam requires it.
- No overlap with 11.4.6's three drift assertions — this card's guards are named and distinct.
Context refs
vitest.config.ts— the per-file coverage-threshold map and its documented carve-out format.tests/api/v1/story-gate.test.ts·tests/api/v1/work-item-story-gate.test.ts— the two shipped story gates whose shape this follows.tests/helpers/v1RouteAudit.ts—declaredScopeByMethod()for the registry↔route scope seam.tests/helpers/db.ts·tests/fixtures/apiV1Fixtures.ts— the real-Postgres and real-call harnesses.- Blockers: 11.4.3 · 11.4.4 · 11.4.5 · 11.4.7 · 11.4.8 — every code subtask of this story in this repo. Sibling guard: 11.4.6. Parent story: 11.4.