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-2232Done

11.6.6 The DRIFT GUARD in CI — a field added on one surface and forgotten on the other fails the build

The story's headline: the mechanism that makes "the two surfaces cannot drift" a fact CI holds rather than a property people maintain. Every tool is derived by now — this is what stops the next one from not being.

What to build

  1. The guard, running over the DERIVED shared-resource set (from lib/api/v1/openapi/registry.ts, per 11.6.2) rather than a hand-written list: for each resource exposed by both surfaces, assert the MCP payload and the REST response validate against the SAME schema.
  2. The failure is the deliverable. Prove the guard bites: add a field to one surface's schema in a fixture and assert the guard FAILS. A guard nobody has watched fail is a guard nobody knows works — and this one's entire value is what it does on a day nobody is looking.
  3. Coverage is asserted, not assumed. The guard reports which resources it checked, and a resource in the derived set with no corresponding check fails rather than being skipped. Same for tools: derived or explicitly exempt, nothing in between.
  4. Where it runs. Wire it into the CI lane that already runs the MCP and v1 suites, with real Postgres where the comparison needs real rows. It is a required check, not an advisory one — an advisory drift guard is a report nobody reads.

What the guard does NOT freeze

Say this in the code, prominently, because the next prompt-tuning pass will read the guard before it reads this card: tool names, tools/list descriptions, argument names and scopes are NOT frozen and SHOULD churn. The guard covers the DATA SHAPE only — the half with a second consumer. A contributor who reads a red check as "I may not reword a tool description" will route around the guard, and that is a worse outcome than the drift it prevents.

Scope BOUNDARY

Ends at the guard and its wiring. It does NOT re-base any tool — every family landed already (11.6.3 / 11.6.4 / 11.6.5). It does NOT change a schema on either surface: if the guard finds a real divergence when it first runs, that is a defect to REPORT against the owning card, not to silence by widening a schema until both sides fit. It does NOT gate on tool prose, arguments or scopes.

Acceptance criteria

  • For every resource in the derived shared set, the guard validates the MCP payload and the REST response against one schema, and the run names the resources it covered.
  • The guard FAILS on a deliberately introduced one-sided field — asserted in both directions (added on REST only, added on MCP only), because a one-directional guard is half a guard.
  • A resource in the derived set with no check, or a registered tool that is neither derived nor exempt, fails the run rather than passing silently.
  • The guard is a REQUIRED check in the CI lane, not advisory.
  • The code states, at the guard's definition, exactly what is frozen (data shape) and what is deliberately free (names, descriptions, arguments, scopes) — and points at the reason.
  • If the guard's first real run surfaces an existing divergence, it is filed as a card against the owning story and cited here; it is not resolved by relaxing the guard.
  • The per-file coverage floor (≥90%) holds on every new file.

Context refs

  • 11.6.2 — the derived shared-resource set and the exemption registry this guard reads.
  • lib/api/v1/openapi/registry.ts · lib/mcp/registry.ts — the two registries whose intersection the guard walks.
  • tests/api/v1/openapi-operations-coverage.test.ts — the shipped precedent for a registry-walking totality test; copy its shape.
  • tests/helpers/v1RouteAudit.ts — the other shipped guard over this boundary, and the model for stating a rule's intent beside its assertion.
  • tests/mcp/tool-coverage.test.ts — the existing MCP-side coverage test this must not duplicate or contradict.
  • Story: 11.6.