MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-3605

Planning bug: MOTIR-3595 plans a cross-repo READ seam no card creates — "read the plan's proposals through core" has no producer

Done
Description

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.

What the plan said

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.

What exists

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:

routeanswers
GET /api/internal/ai/plan-treethe project's work-item skeleton
GET /api/internal/ai/get-item · get-subtreework items
POST /api/internal/ai/search-work-items · similar-work-itemswork items
POST /api/internal/ai/validate-plantakes 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.

Why it would have failed silently

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.

The rule this instances

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.

Acceptance criteria

  1. 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.
  2. It names the tell above, so a skeleton pass can grep for it rather than re-derive it.
  3. It states why this class is hard to see: the two halves are in different cards, in different repositories, and each reads complete on its own.
  4. The fixture is recorded with its numbers — four committed-tree reads, none of which can answer about a proposal.

Context refs

  • 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.