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

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 structuredContent from the shared work-item schema or a declared narrowing of it; no as unknown as cast 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_ready and search_work_items carry their dependencies block from the shared schema, and lib/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 zod and zod/v4.
  • The per-file coverage floor (≥90%) holds on every changed file.

Context refs

  • 11.6.2 — the seam, the toolOk typing 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.tsworkItemDetailSchema, workItemSummarySchema, workItemRefSchema, readinessSchema, commentSchema; lib/api/v1/ready/schema.tsreadyItemSchema.
  • 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 toEqual that fails solely because a v1 field was ADDED beside the existing ones — the added field must be named in the PR body; (2) the key → identifier change and its numericKey companion, which is the ONE non-additive change in Story 11.6 and is named in the ADR. Its only consumer is tests/mcp/search.test.ts (three { key: number } cast sites); @motir/cli never 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.