(planning) ADR Amendment 2's schema-ownership split silently OMITS Story 11.1's own two endpoints — `/api/v1/me` and `/api/v1/workspaces` had no owner, so 11.4.5 had to author their shapes
Found at run time by motir run MOTIR-1854, executing 11.4.5. Not a code defect — a gap in a decision record, which is why it is filed against the story that owns those endpoints rather than fixed silently inside 11.4.
The finding — verified against origin/main
ADR Amendment 2 (docs/decisions/public-api-conventions.md, 2026-08-03) assigns per-resource zod response schemas by story, exhaustively as it reads:
- "11.2 owns the work-item resource schemas … in
lib/api/v1/workItems/" - "11.3 owns the project, sprint, backlog and ready-set schemas, in its own per-resource modules"
- "11.4 owns the SHARED envelope, error and pagination schemas … and authors no per-resource shape."
Story 11.1's own two endpoints are in none of those three sentences. GET /api/v1/me (11.1.2, MOTIR-1858) and GET /api/v1/workspaces (11.1.3, MOTIR-1859) shipped in July, before Amendment 2 existed, and shape their rows inline in the route handler — correctly, and for the reason the /me route states in its own comment: "the response is shaped explicitly rather than spread, because verify returns the raw Prisma User row and a public API must never leak one". The inline FORM is exactly what Amendment 2 was written to retire, and it retired it everywhere except the two routes that predate it.
git grep on origin/main confirms there is no zod schema for either shape anywhere in the tree.
Why it surfaced only now, and what 11.4.5 did about it
Declaring an OpenAPI operation needs a response schema. For these two there was none, leaving two choices and no third:
- Leave two shipped endpoints out of the published document — the "a reference that covers some of an API is worse than one that covers none" failure 11.4.5 exists to close, and a direct violation of its own first acceptance criterion ("every
route.ts… has an operation declared for each HTTP method it exports"). - Author the two shapes inside Story 11.4 — which its scope boundary forbids ("It authors no schema, shared or per-resource").
11.4.5 took (2), deliberately and with the reasoning recorded in the code, because (1) fails a stated acceptance criterion while (2) violates a boundary written to prevent RE-declaring shapes that already have an owner — and these have none. The module is lib/api/v1/identity/schema.ts, its header names this bug, and the schemas are proven honest against the real routes (tests/api/v1/openapi-operations-coverage.test.ts drives both with a real PAT and parses what they actually return, rather than against a fixture written from the same assumption). Neither route was changed, per 11.4.5's "the declaration follows the route" rule.
What this card decides
- Where the identity/workspace schemas belong long-term.
lib/api/v1/identity/schema.tsis where 11.4.5 put them; the question is whether Story 11.1 adopts that module as its own (and, if so, whether/meand/workspacesshould MAP through it the way 11.2's and 11.3's routes map through theirs) or whether a different home is right. - Whether the two routes should map through the schema rather than beside it. Today the schema DESCRIBES what the routes return; every other v1 resource has the route emit the schema's output. The asymmetry is small but real: a field added to
/me's inline literal would not fail typecheck, only the parse test. - Amend Amendment 2 so the split is TOTAL. The clause reads as an exhaustive assignment and is not one. Whatever the answer above, the amendment gains a fourth sentence naming who owns Story 11.1's endpoint shapes, so the next reader cannot conclude — as this run did — that the split covers every endpoint when it covers eleven twelfths of them.
Acceptance criteria
- Amendment 2's ownership clause names an owner for every
/api/v1endpoint's response shape,/meand/workspacesincluded — checked by walkingapp/api/v1rather than by re-reading the three sentences. - The identity/workspace schemas have a recorded home, and if that home is not
lib/api/v1/identity/schema.tsthe module is moved (it has no other consumer than the operation declarations). - If the decision is that the routes should MAP through the schema, that is its own subtask with its own PR — it changes response-shaping code and is not a documentation edit.
lib/api/v1/identity/schema.ts's header comment is updated to point at whatever this card decides, replacing its "recorded plan gap" note.
Context refs
docs/decisions/public-api-conventions.md— Amendment 2's ownership clause (the three sentences), and Amendment 4 (which settled the emission mechanics on top of it).app/api/v1/me/route.ts·app/api/v1/workspaces/route.ts— the two endpoints, and their own comments on why they shape explicitly.lib/api/v1/identity/schema.ts— what 11.4.5 authored, and why.tests/api/v1/openapi-operations-coverage.test.ts— the proof the schemas match the real responses.lib/api/v1/workItems/schema.ts·lib/api/v1/projects/schema.ts— the owned-and-mapped-through pattern the two odd endpoints do not follow.