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

11.5.2 The generated v1 client types + their freshness guards — one command, a committed artifact, and a CI diff that cannot be argued with

The pipeline that turns the emitted OpenAPI document into the types and validators packages/cli compiles against — implementing 11.5.1's Q1 and Q2 exactly as that ADR pins them. It ships no client behaviour: nothing calls the new module yet.

What to build

  1. The generation command — one script, runnable as a package script, that produces the generated module(s) into packages/cli/src/api/ (or wherever the ADR pinned) from the document, with no network and no running server. Per the ADR, the source is the in-repo emitter, not the HTTP route.
  2. The committed artifact, checked in and marked generated in its own header — the file a reader must not hand-edit, saying which command regenerates it.
  3. Guard A — the artifact is FRESH. Regenerate in CI and fail on any diff. This is the whole reason a committed generated file is trustworthy rather than a snapshot of whenever someone last remembered.
  4. Guard B — the SERVED spec matches the emitter. Assert app/api/openapi/v1.json's response body equals emitOpenApiDocument()'s output, so the public URL external integrators generate from (ADR Amendment 4 Q3) and the bytes this pipeline consumes can never diverge. Cheap: the route is force-static, takes no input, and the emitter is documented deterministic.
  5. A round-trip smoke assertion — one representative response shape from each of the four shipped resource families (work item, project, sprint, ready row) validates against its generated validator, and a deliberately-corrupted copy fails with an error naming the offending field. This is what proves the pipeline produced something usable, rather than a file that merely exists.

Scope BOUNDARY

Ends at generated artifacts plus their guards. It does NOT touch MotirClient, any command, render.ts, or the hand-written interfaces — those are still the live types when this card lands, and deleting them is 11.5.6's job once nothing reads them. It does NOT add or change any /api/v1 endpoint or schema. It does NOT change the emitter or the spec route — if Guard B fails on landing, that is a real defect to report, not a reason to edit the emitter here.

Acceptance criteria

  • One documented command regenerates every generated artifact from a clean checkout with no server running and no network access, and running it twice produces byte-identical output.
  • The generated artifact is committed, carries a do-not-edit header naming its regeneration command, and is excluded from lint/format churn the way the repo's other generated files are.
  • Guard A fails a CI run in which the emitter's output and the committed artifact disagree — proven by a test that drives the guard with a deliberately stale artifact, not by trusting the script.
  • Guard B asserts the served /api/openapi/v1.json body equals the emitter's output.
  • A valid sample of each of the four shipped resource families validates; a corrupted copy of each fails with an error identifying the field, asserted per family.
  • Every generated type the CLI will consume is exported from one module boundary, so a later card imports from one place rather than reaching into generated internals.
  • No file in packages/cli/src imports the generated module yet, and the CLI's behaviour is unchanged — asserted by the existing suites passing untouched.
  • The per-file coverage floor (≥90%) holds on every new hand-written file; the generated artifact itself is excluded from coverage, as generated code is elsewhere in the repo.

Context refs

  • 11.5.1 — the ADR this implements; Q1 (generator + validator) and Q2 (location, commit, both guards) are its instructions.
  • lib/api/v1/openapi/emit.tsemitOpenApiDocument() and its determinism claim.
  • app/api/openapi/v1.json/route.ts — Guard B's subject; note it is deliberately NOT a withV1Route handler.
  • lib/api/v1/workItems/schema.ts · projects/schema.ts · sprints/schema.ts · ready/schema.ts — the four families the smoke assertion samples.
  • packages/cli/package.json + packages/cli/tsup.config.ts — where the generation script and any build ordering land.
  • packages/cli/vitest.config.ts — the per-file coverage gate a new file joins, and where a generated-file exclusion goes.
  • Story: 11.5.