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

11.4.4 The operation registry + the OpenAPI 3.1 emitter, and the route that serves the spec — proven on the work-item resource

Repo: motir-core. One PR. The machinery that turns declared schemas into a document, plus the door that serves it. This is where "the spec is the schema source" becomes a mechanism rather than an intention.

Nothing today connects a schema to an endpoint: lib/api/v1/workItems/schema.ts knows the work-item shape and app/api/v1/work-items/[key]/route.ts knows the path, and no value in the repo says they belong to the same operation. That missing value is the registry.

What to build

  1. The operation descriptor + registry. A typed V1Operation — method, path template, path/query parameters, request-body schema, the response envelope it returns (one of the two 11.4.3 declares), the required scope, the error statuses it can raise, and a summary — and a registry keyed by `${METHOD} ${path}`. Build it the way 11.4.1's Amendment 4 pins it (per-resource operations.ts modules assembled by one registry, unless the amendment says otherwise), and mirror the totality discipline lib/mcp/registry.ts + lib/mcp/scopes.ts already use: an operation that names no scope must fail typecheck, not review.
  2. The emitter. Assemble the OpenAPI 3.1 document from the registry plus the schema modules: info, servers, paths with one operation each, components holding the resource schemas and 11.4.3's shared envelopes / error body / rate-limit headers, and the bearer security scheme applied per operation with its scope. Each collection operation references the envelope its route actually returns — the ranked one carrying totalCount or the plain cursor page — per Amendment 3 Q2.
  3. Key the emitter by API MAJOR version. There is one document today and that is the degenerate case, not the model: v2 must be a second document, not an edit of the first. info.version means the API's version, not the app's release number — state which in the code.
  4. Declare the WORK-ITEM operations as the proving resource (app/api/v1/work-items/** and the project-scoped work-item collection). One resource is enough to prove the machinery end to end; 11.4.5 declares the rest.
  5. Serve the document at the URL Amendment 4 pins, unauthenticated and cacheable. If that URL sits under app/api/v1, the shipped route audit will flag ittests/helpers/v1RouteAudit.ts:38 walks every route.ts there and raises bypasses-wrapper for a handler not wrapped in withV1Route (tests/helpers/v1RouteAudit.ts:84-99), and the wrapper authenticates. Implement the exemption exactly as Amendment 4 specifies it, and assert its bounds: it applies to that one path, and that file authenticates nothing, touches no database, reads no user input.

Scope BOUNDARY

Ends at the machinery, the work-item operations and the served route. It declares no operations for projects, sprints, the backlog, the ready set, workspaces or /me — those are 11.4.5, and the document is legitimately incomplete until that card lands. It authors no schema: the shared ones are 11.4.3's and the per-resource ones are already shipped. It builds no route↔spec CI guard — that needs the complete registry and is 11.4.6. It renders no page. It changes no existing endpoint's behaviour, path or response.

Acceptance criteria

  • A typed operation registry exists, keyed by method + path, and an operation missing its scope or its response schema fails pnpm typecheck — proven by a type-level test or an equivalent compile-failure assertion.
  • The emitter produces a document that validates as OpenAPI 3.1 against a real validator, not a hand-written shape check.
  • Every work-item operation appears with its method, path, parameters, request body where it has one, response schema, required scope and error statuses; the collection operations reference the correct one of the two envelopes.
  • The bearer security scheme is applied per operation with the scope that operation requires, and that scope equals the scope its route file declares — asserted, not assumed.
  • The emitter takes the API major version as input and produces a distinct document per version; a test drives it with a second version and gets a second document, not a mutated first.
  • The spec route returns the document with a JSON content type and no authentication, and a request carrying no Authorization header succeeds.
  • The route-audit exemption (if the pinned URL requires one) is implemented and BOUNDED by assertions: it names exactly one path, and a test proves a second exempted path, or an exempted file that authenticates or reads the database, FAILS.
  • New files join the per-file coverage thresholds in vitest.config.ts at the ≥90% floor.

Context refs

  • lib/api/v1/openapi/11.4.3's shared schemas, envelopes and security scheme this assembles from.
  • lib/api/v1/workItems/schema.ts — the work-item request + response schemas, declared beside their routes precisely so this card can emit from them (see its // Story 11.4 emits the OpenAPI operations from this module note at line 521).
  • app/api/v1/work-items/** · app/api/v1/projects/[projectKey]/work-items/route.ts — the routes the proving operations describe.
  • lib/mcp/registry.ts · lib/mcp/scopes.ts — the registry-driven totality pattern.
  • tests/helpers/v1RouteAudit.ts — the route walker and the bypasses-wrapper rule the spec route collides with.
  • lib/api/v1/route.tswithV1Route, and why an unauthenticated route cannot use it.
  • docs/decisions/public-api-conventions.md — Amendment 3 Q2 (envelope choice per operation), Amendment 4 (registry shape, spec URL, exemption).
  • Blocker: 11.4.3. Parent story: 11.4.