Type · planning mistake (an unverified precondition — a cross-repo seam with no owning card)
Discovered in · motir run MOTIR-3595 (the parent-run), reaching MOTIR-3600.
Correction · ALREADY APPLIED — the route shipped on the parent branch under MOTIR-3598. This card is the telemetry, not the work.
MOTIR-3600 ((motir-ai) the revise_plan handler) states its first build step as:
The handler — read the plan's proposals through core, seed the registry from them, run the pass…
and its criterion 2 as:
The pass sees the plan it is revising: the proposal registry is seeded from the plan's existing proposals BEFORE the model's first turn.
Nothing in motir-core answers that read, and no card in the story creates it. Every internal seam a job token can reach answers about the committed tree:
| route | answers |
|---|---|
GET /api/internal/ai/plan-tree | the project's work-item skeleton |
GET /api/internal/ai/get-item · get-subtree | work items |
POST /api/internal/ai/search-work-items · similar-work-items | work items |
POST /api/internal/ai/validate-plan | takes a planId and returns a verdict, never the items |
A proposal is not a work item, so none of them can see one. MOTIR-3598's card names the write pair (correctProposal / withdrawProposal) and no read; MOTIR-3599's boundary is explicitly "no proposal writes — those are the internal-route card"; MOTIR-3601 is UI. The seam is named in prose by the card that CONSUMES it and owned by nobody.
src/llm/proposalRegistry.ts is populated by a pass's own output and is empty at the start of a job. A handler that cannot read the plan therefore runs against an empty registry and proposes a tree from scratch — which is re-planning, the exact thing this story exists to replace — while every signal reads green: the job succeeds, proposals are written, the plan changes. The card's own body says so ("or the pass will reason about an empty tree and propose a plan from scratch") and still names no producer for the read that prevents it.
plan-rules/phase-deepen.md's precondition-verification rule, and plan-rules/core.md's a deferral is a card: a capability a card CONSUMES must be produced by a card, and naming it in the consumer's prose is not producing it. The (motir-ai) / (motir-core) split makes this class easier to miss — the consumer and the producer are in different repositories, so the gap is invisible from either card alone.
The tell, and it is grep-able: a card whose build steps contain "read X through core" / "through the sibling's route" where no sibling card's title or acceptance criteria mention that route.
plan-rules/phase-deepen.md's precondition-verification rule gains the CROSS-REPO limb: when a card in repo A consumes a route, read or capability in repo B, the plan must contain a card in repo B whose acceptance criteria PRODUCE it — a phrase in the consumer's body is not a producer.motir-meta/prompts/plan-rules/phase-deepen.md — the rule this amends.motir-core/app/api/internal/ai/plan-proposals/route.ts — the GET that closed it, shipped under MOTIR-3598.motir-ai/src/llm/proposalRegistry.ts — the registry whose emptiness is the failure mode.