Vitest gate (motir-core) — the CONFIGURED manifest seam end to end, and both arms of the unconfigured case
Opened by Zhu Yue ·
Type: test · Executor: coding_agent · Repo: motir-core · ONE PR. The story's per-repo coverage + integration gate for the application host. The motir-marketing gate is the other one — one repo, one suite, one PR.
It runs LAST in this repository, after every motir-core code card has merged, because it measures their real, merged coverage and drives their real seams. Real Postgres, not mocks.
⚠️ RE-SCOPED 2026-09-01 — the ABSENCE clauses left with the deletion
The deletion moved out of this story (plan-rules/kind-container.md's merge-count check — see MOTIR-3909's own amendment), so the clauses that could only be asserted AFTER it are now the post-deletion vitest gate's, in the deletion story:
- the no-
content/legal-reader guard and its red run, - catalogue parity after the
legal.*namespace was split.
Both were CUT from this card rather than duplicated, so nothing is asserted twice and nothing was dropped. This card's blocked_by edge to the deletion is gone with them; what remains is the CONFIGURED manifest seam, which is fully assertable with content/legal/ still in the tree because nothing surviving reads it.
⚠️ Do not re-add an absence assertion here on the grounds that it would be cheap. Asserted in this story it passes for a reason that has nothing to do with the guard: the files are still present and simply unread, so the guard is measuring the wrong state and would go green whether or not the reader was really gone.
Its three jobs at run time — not a plan-time case list
- Coverage floor. Run coverage over this story's changed surface in this repository and write whatever is missing to reach the project's per-file gate (≥90% branch/fn/line,
motir-core/CLAUDE.md), plus the five filesvitest.config.tsalready pins at their own thresholds —lib/legal/{consent,documents,reconsentGate}.ts,lib/repositories/legalAcceptanceRepository.ts,lib/services/legalAcceptanceService.ts. Do not pre-subtract what the feature cards' own units cover; that they cover it is the expected normal, and this gate tops up the seams BETWEEN them. - The integration seam, which for this story is one wire: the manifest value →
documents.ts→consent.ts→legalAcceptanceService→ theLegalAcceptancerows →resolveOutstanding→ the rendered row'shref. Drive one card's real output back through the next card's real consumer. The units on either side mock the middle, and this is the only place the whole wire is exercised. - The contract guards coverage cannot see — below.
The guards
⚠️ NOTHING IN THIS REPOSITORY READSMOVED to the post-deletion vitest gate (2026-09-01) — the files are still in this repository when this story merges, so the guard would pass here for the wrong reason. Its own sentence is why: a manifest that works proves the new path, never that the old one is gone, and neither does a guard run before anything left.content/legal/ANY MORE.- The materiality rule survives the source swap. Over a manifest: a MINOR or MAJOR bump on one of the three re-consent slugs HOLDS the user; a PATCH bump does not, because
content/legal/terms.md§14 promises a clarification takes effect when published. This isconsent.ts's rule, asserted through the seam rather than in isolation. - The unconfigured arm, on BOTH sides. With no manifest:
recordAcceptancewrites zero rows and does not throw;resolveOutstandinganswers[]; a signed-in request is not held; sign-up renders its unconfigured form and the rail has no Legal row. Assert each of those, not "nothing errored" — every one of them is a deliberate empty-set arm, and the whole failure mode this story guards against is exactly that arrangement being silently correct. - A malformed manifest cannot hold the product. An entry whose
versiondoes not parse must not reachlistLegalDocuments(), becauseisMaterialChangetreats an unparseable version as material and would hold every signed-in reader at/re-consent. - Tenancy isolation on the acceptance table.
legalAcceptanceRepositorywrites underwithUserContext; one user's acceptance rows must not be visible to another. A fixture in which the actor's view and the true population DIFFER — a test whose actor happens to see everything cannot tell a scoped read from an unscoped one. Catalogue parity after theMOVED to the post-deletion vitest gate (2026-09-01) — nothing splits that namespace in this story.legal.*namespace was split.
⚠️ Read the lane's own configuration before writing a line in it
The manifest is a server-side, process-wide value, so a spec that needs it CONFIGURED has no per-test override and no client seam a request stub can reach. Name the exact mechanism this suite uses to set it, and confirm the runner reaches it, before writing the assertions — a guard in a lane that cannot reach the asserted state passes on unfixed code and stays green for ever. Where the configured arm cannot be reached from this suite at all, that arm belongs in the lane that sets it (see the E2E card) and this card says so rather than asserting the harness.
⚠️ What this card may NOT assert
- Nothing about
motir-marketing. The seven rendered documents, the reachability glob and the page-side subprocessor check are the other gate's, and a copy of them here would test a copied file. - Nothing about the redirect. MOTIR-3884's.
- Nothing about the deployed manifest. The provisioning card reads that back from the platform; a repository suite cannot.
Acceptance criteria
- Coverage over this story's changed surface in
motir-coremeets the per-file gate, and the five pinned files stay at their configured thresholds; the PR body shows the run. - The full manifest seam is driven end to end against real Postgres, from a configured manifest to a rendered
href, in one test — not a chain of unit tests each mocking its neighbour. The no-MOVED to the post-deletion vitest gate (2026-09-01).content/legal-reader guard exists, and the PR shows it going RED…- The materiality guard asserts both directions — a MINOR bump holds, a PATCH bump does not — through the seam.
- All four unconfigured assertions are present and each is an assertion about a specific behaviour, not about the absence of an exception.
- The malformed-manifest guard exists and is shown red against a valid-looking entry with an unparseable version.
- The tenancy fixture has the actor's view and the true population DIFFER, and the PR body says so explicitly.
Catalogue parity passes.MOVED to the post-deletion vitest gate (2026-09-01).- The mechanism this suite uses to configure the manifest is named in the spec's own comment, and the PR body confirms the runner reaches it — or names which arm was moved to the E2E lane and why.
- No test is deleted because its subject moved; anything re-pointed is re-pointed to a shipped symbol, and the PR body maps every assertion to one.
Context refs
motir-core/vitest.config.ts— the per-file thresholds on the five legal filesmotir-core/lib/legal/documents.ts·consent.ts·reconsentGate.ts— the seam's upper halfmotir-core/lib/services/legalAcceptanceService.ts·lib/repositories/legalAcceptanceRepository.ts— its lower half, andwithUserContextmotir-core/tests/legal/— the six surviving suites this composes withmotir-core/CLAUDE.md— the coverage gate and the real-Postgres disciplinemotir-core/messages/en.json·messages/zh.json— the parity subject- the registry card · the link-surfaces card · the guard card — every
motir-corecode card this measures; all threeblocked_by - the post-deletion vitest gate — took this card's absence clauses on 2026-09-01, in the deletion story; the deletion
blocked_byedge went with them
Advisory dispositions
- The remaining
referenceadvisories name cards this one's Boundary excludes. A boundary exists to say a deliverable is somebody else's, and naming the owner is what makes the exclusion checkable — so the reference is deliberate and no edge is owed.
Discussion
No comments yet.
Adding to this discussion signs you in on app.motir.co and brings you back to this request.