11.6.3 Re-base the WORK-ITEM family onto the shared schemas — the reads that carried the founding defect, plus every write that returns an item
Apply 11.6.2's seam to every tool whose output is a work item or a work-item collection. Mechanical once the mechanism exists — the value is in the two reads that started this.
The tools
search_work_items · list_ready · next_ready · claim_next_ready · create_work_item · update_work_item · transition_status · link_work_items / unlink_work_items · archive_work_item / unarchive_work_item · change_kind · move_to_parent · delete_work_item · add_comment. (get_work_item landed with the seam.)
list_ready and search_work_items are the point. They are the two tools that grew a dependencies block while get_work_item did not, and lib/mcp/dependencyEdges.ts's "ONE seam, TWO tools" comment is the shipped record of that partial coverage. After this card the block comes from the shared schema and the comment describes history rather than a live asymmetry — update it to say so.
Subsets are DECLARED, not hand-built
Several of these legitimately return less than the REST shape: a ready row is not a full work item, next_ready returns a dispatch projection, a write returns a confirmation. Each of those is fine and each must be a declared narrowing of the shared schema — .pick, .omit, or an explicitly derived type — never an independently authored object that happens to look similar. A narrowing that drifts fails to compile; a look-alike drifts silently, which is the whole subject of this story.
Scope BOUNDARY
Ends at the work-item resource family. It does NOT touch projects, sprints, backlog or identity (11.6.4) or the work-loop tools (11.6.5). It does NOT ship the CI drift guard (11.6.6). It does NOT change any tool's name, arguments, scope, description text or human-readable content block. It does NOT change /api/v1: if a shared schema turns out to be wrong for a tool's legitimate needs, that is a finding to report against the owning story, not a widening to make here.
Acceptance criteria
- Every tool listed above builds its
structuredContentfrom the shared work-item schema or a declared narrowing of it; noas unknown ascast and no hand-authored object remains in any of them. - Each narrowing is expressed as a derivation from the shared schema, asserted by a type-level test that fails when the base shape changes incompatibly.
- 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. list_readyandsearch_work_itemscarry theirdependenciesblock from the shared schema, andlib/mcp/dependencyEdges.ts's "ONE seam, TWO tools" comment is corrected to describe what is now true.- The totality mechanism accepts every tool in this family without an exemption entry — none of them is legitimately exempt, so an entry appearing here is a defect.
- No file imports both
zodandzod/v4. - The per-file coverage floor (≥90%) holds on every changed file.
Context refs
- 11.6.2 — the seam, the
toolOktyping and the exemption registry this card uses without extending. lib/mcp/tools/searchWorkItems.ts·listReady.ts·nextReady.ts·claimNextReady.ts·createWorkItem.ts·updateWorkItem.ts·transitionStatus.ts·linkWorkItems.ts·archiveWorkItem.ts·changeKind.ts·moveToParent.ts·deleteWorkItem.ts·addComment.ts— the subjects.lib/mcp/dependencyEdges.ts— the "ONE seam, TWO tools" comment to correct.lib/api/v1/workItems/schema.ts—workItemDetailSchema,workItemSummarySchema,workItemRefSchema,readinessSchema,commentSchema;lib/api/v1/ready/schema.ts—readyItemSchema.tests/mcp/search.test.ts·dependency-edges.test.ts·write-tools.test.ts·edit-archive-tools.test.ts·link-tools.test.ts·change-kind.test.ts·move-to-parent.test.ts·delete-tool.test.ts·integration-state.test.ts— the suites that must pass unmodified.- Story: 11.6.
⚠️ Amended 2026-08-06 (MOTIR-2227 / MOTIR-2276) — what the "suites pass unmodified" criterion actually forbids
Building this card surfaced a collision the plan had not compared for: key means the PROD-<n> identifier on /api/v1 and on MCP's ready rows, but the NUMERIC key on MCP's work-item rows (WorkItemSummaryDto.key / WorkItemListItemDto.key). A live get_work_item returns children as {"key":2227,"identifier":"MOTIR-2227"}. A row already carrying key: 2227 cannot additively gain key: "MOTIR-2227", so this card's "observable payload UNCHANGED / suites pass unmodified" criterion and the story's "both surfaces validate against the SAME schema" criterion are jointly unsatisfiable as written.
Decided in ADR Amendment 7 Q6 + its addendum (docs/decisions/public-api-conventions.md), not improvised here. The criterion is REPLACED by a rule about what may change:
- Still a violation, and still the tell the criterion was written to catch: a key REMOVED, a key RENAMED, or a VALUE altered. Fix the code, never the expectation.
- Permitted, and only these two: (1) a whole-payload
toEqualthat fails solely because a v1 field was ADDED beside the existing ones — the added field must be named in the PR body; (2) thekey→ identifier change and itsnumericKeycompanion, which is the ONE non-additive change in Story 11.6 and is named in the ADR. Its only consumer istests/mcp/search.test.ts(three{ key: number }cast sites);@motir/clinever reads a numeric key (grep -rn "key: number" packages/cli/src/→ no matches).
Everything else about the criterion stands: the suites are frozen, and an edit outside those two categories is the defect.