Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-2187Done

11.4.6 The route↔spec conformance guard — three drifts fail CI: a route with no operation, an operation with no route, and a response that does not match its declared schema

Repo: motir-core. One PR. The check that makes "the spec is the single source of the response schemas" a fact rather than an aspiration. Everything before this card produces a document that is correct today; this card is what stops it quietly becoming wrong, and it is the only deliverable in the story whose absence would not be noticed for months.

Three drifts, each of which must FAIL:

  1. A /api/v1 route with no operation in the spec. Someone adds an endpoint and the document silently omits it — the drift that turns a "complete" reference into a partial one.
  2. A spec operation naming no route. An endpoint is renamed or removed and the document keeps advertising it — worse than an omission, because a client builds against it and gets a 404.
  3. An endpoint whose REAL response does not validate against its declared schema. The drift that makes the other two look fine: the operation exists, the path matches, and the body has quietly changed shape.

Drift 3 must be driven against a real request and a real response — call the route, take what it actually returned, validate that against the schema the document declares for it. Validating a fixture written from the same schema tests the fixture; the shipped harness already does the real thing (tests/fixtures/apiV1Fixtures.ts's createV1Caller / createV1ProjectCaller, real Postgres via tests/helpers/db.ts, and tests/api/v1/conformance.test.ts's external-HTTP pattern where a route needs real transport).

Each of the three is proven by deliberately introducing it. A guard that has never been shown to fail is not a guard — the same argument tests/helpers/v1RouteAudit.ts makes for itself in its own header, and the pattern to copy: run the rule against the real tree and against a synthetic violation.

No silent caps. Where an operation genuinely cannot be driven by the harness, it is listed explicitly with the reason, and the guard fails if that list grows without one. A quietly-skipped operation reads exactly like a covered one.

This is a vitest suite, so it runs inside the existing test matrix in .github/workflows/ci.yml and rides the required CI complete check — add a workflow job only if something here genuinely cannot run there, and say why if so.

Scope BOUNDARY

Ends at the guard. It declares no operation and writes no schema — a gap it finds in the registry is fixed by amending 11.4.5's declarations, not by loosening the check. It changes no endpoint's behaviour or response shape: if a real response disagrees with its declared schema, the DECLARATION is corrected when the route is right, and a bug is filed when the route is wrong — the check is never relaxed to accommodate either. It is not the story's coverage gate (11.4.9 owns the ≥90% floor, the inter-card seams and the architecture guards) and it does not test the reference PAGE (11.4.10 does).

Acceptance criteria

  • The guard walks the real route tree and the real registry and passes against main's current state.
  • Drift 1 fails: a synthetic route file with an exported handler and no operation is rejected, naming the path.
  • Drift 2 fails: a synthetic operation whose path matches no route file is rejected, naming the operation.
  • Drift 3 fails: an operation whose declared schema is mutated away from the route's real response is rejected, naming the operation and the offending field.
  • Response validation runs against a REAL response from a real call — no fixture generated from the schema under test.
  • Every operation in the registry is either exercised by drift 3 or listed as undrivable with a written reason, and a test fails if an operation is neither.
  • The suite runs in the existing CI vitest matrix; no route, schema or endpoint file changes.
  • The guard's own files join the per-file coverage thresholds in vitest.config.ts where the project's convention requires it.

Context refs

  • tests/helpers/v1RouteAudit.ts — the route walk, and the run-it-against-a-synthetic-violation pattern this guard copies.
  • tests/fixtures/apiV1Fixtures.tscreateV1Caller / createV1ProjectCaller, the shipped way to make a real authenticated v1 call.
  • tests/helpers/db.ts — the real-Postgres harness; tests/api/v1/conformance.test.ts — the external-HTTP client pattern for what in-process calls cannot reach.
  • tests/api/v1/story-gate.test.ts11.1.5's architecture-guard suite, the closest sibling in shape.
  • .github/workflows/ci.yml — the test matrix this rides and the CI complete required check.
  • Blocker: 11.4.5. Parent story: 11.4.