PLANNING BUG — 11.6's family cards froze their MCP suites "unmodified" while the story's own core change makes one of them false: `key` means the numeric key on MCP work-item rows and the identifier on `/api/v1`
A RECORD card — the correction already shipped with 11.6.1's ADR amendment and the run continued. Filed so the planning defect is on the record, not to schedule work.
What the plan asserted
Every family card under 11.6 — 11.6.2, 11.6.3, 11.6.4, 11.6.5 — carries a criterion of the form:
"Every tool's observable payload is UNCHANGED — same keys, same values, for the same rows — asserted by
tests/mcp/'s existing suites passing unmodified. An edit to an expected payload in those files is the tell that this card changed behaviour it promised not to."
Simultaneously the STORY requires that "for each resource exposed by BOTH surfaces, a CI test asserts the MCP payload and the REST response validate against the SAME schema", and 11.6.8 requires both surfaces to "carry the same values under the same keys".
Why it could not hold — rung 2, observed live
The two surfaces do not merely differ in richness; they disagree about what key means, and so does the MCP surface with itself:
| Row | key is |
|---|---|
/api/v1, every resource (workItemKeySchema, /^[A-Z][A-Z0-9]*-\d+$/) | the PROD-<n> identifier |
MCP list_ready / next_ready (ReadyItemDto.key) | the PROD-<n> identifier |
MCP search_work_items (WorkItemListItemDto.key) | the numeric key |
MCP get_work_item children (WorkItemSummaryDto.key) | the numeric key |
A live get_work_item MOTIR-1856 returns children as {"key":2227,"identifier":"MOTIR-2227", …}.
There is no additive reconciliation: a row that already carries key: 2227 cannot also carry key: "MOTIR-2227". So the two criteria are jointly unsatisfiable on the work-item family — which is the family the story exists for.
The general form the plan also missed
Even away from the collision, the surfaces are not subsets of each other (MCP carries id and an assignee object; v1 carries assigneeId), so "derive from the shared schema" necessarily changes payloads at least additively. The family cards' "unmodified" criterion was written as though derivation were a pure refactor. It is not — it is the story's deliverable.
What was decided instead (already shipped)
ADR Amendment 7 Q6 + its addendum (docs/decisions/public-api-conventions.md, MOTIR-2227):
- Resource-valued parts of an MCP payload are the shared schema's output; extras are a declared
.extend, omissions a declared.pick/.omit; the envelope stays MCP's own. Changes are additive only. - The one exception: MCP's
keybecomes thePROD-<n>identifier everywhere and the numeric key is preserved asnumericKey. Blast radius by grep:@motir/clinever reads a numeric key; the only consumer istests/mcp/search.test.ts(three cast sites). - A removed / renamed key or a changed value stays a violation. A whole-payload
toEqualfailing only because a v1 field was ADDED is the one permitted edit, and must name the added field in the PR body.
The lesson
A criterion that freezes a test suite is a good guard against sloppiness and a bad way to state a compatibility promise: it cannot distinguish "the author got lazy" from "the deliverable makes this expectation false". The promise belongs in the card as a rule about what may change (nothing removed, nothing renamed, no value altered) — which a reviewer can apply to a diff — not as a prohibition on touching files, which the story's own core change was always going to violate.
The deeper miss is that the plan asserted the two surfaces were near-aligned without ever comparing a payload. One get_work_item call would have shown key was numeric.
Acceptance criteria
- ADR Amendment 7 Q6 + addendum record the derivation direction and the
keydecision, with the rejected alternatives. (done, MOTIR-2227) - 11.6.2 and 11.6.3 carry an amendment naming the permitted test edits so they cannot be mistaken for the sloppiness they froze against. (done)
notes.htmlcarries the lesson. (done)- No further code change is owed by this card.