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,369
shipped

Motir · Work items

MOTIR-4272To Do

Planning bug: a story's four children each excluded the client half, and the exclusion pointed at a card that did not exist

What the plan got wrong

MOTIR-4054 was decomposed into four children — a design, a store+doors, a stop, and a narration fix. Every one of them is individually well-formed. Together they do not deliver the story's headline promise: a user cannot say anything to a running plan.

The client half — the composer staying usable during a run, the send routing to the mailbox, and the queued treatment — is owned by no card.

The exact tell, and it is grep-able

MOTIR-4067's Scope BOUNDARY reads:

OUT: the composer UI. The thread's input already exists (MOTIR-2226); the PENDING treatment for a queued turn is drawn by MOTIR-4066 and rendered by the card that owns the surface.

There is no card that owns the surface. The exclusion names a referent rather than a key, and nothing checks that the referent resolves. Compare the other three:

cardsays about the composer
MOTIR-4066 (design)OUT: implementation
MOTIR-4067OUT: the composer UI → "the card that owns the surface"
MOTIR-4068IN: the stop control, the stopped/stopping treatment. Silent on a turn
MOTIR-4069IN: narrateFrame and the act-line treatment

Each boundary is defensible on its own. The union has a hole, and the hole is exactly where the story's value is.

Why nothing caught it

  • validate_work_item cannot see it. Its reference family fires on a card naming a not-done work item with no edge. Unowned work has no key to name, so the array is empty and correct.
  • Readiness is green. Every child's blockers resolve; nothing is waiting on anything.
  • The likely-missing-edge severity is about edges between cards that exist. This is an absent card, which is a different object.
  • The design's own allocation did not close it either. plan-rules/type-design.md's GIVES/TAKES sweep asks what an asset gives to each named card. State B is given to nobody, and a sweep over the named set never visits it.

What made it findable

The calendar check (run.md, a done design blocker that merged AFTER the card). The design merged 2026-09-03 10:03Z; all three code cards were authored 2026-08-31. Reading the asset as a spec and diffing its drawn STATES against the children's scope boundaries is what surfaced it — not reading any card.

The correction

Plan cmtlezbvn000hhwphntex5tzc (submitted, planned, awaiting approval) adds the missing card as a sibling under MOTIR-4054, blocked_by MOTIR-4066 and MOTIR-4067. MOTIR-4068 is untouched — it is correct as written and was built in the same run.

The rule that would have caught it at plan time

A scope BOUNDARY that excludes work by pointing at another card must name that card by its MOTIR-<n> key, not by a description of it. A referent that is a phrase cannot be checked; a key either resolves or does not. This is plan-rules/phase-skeleton.md's cite-a-sibling-by-id rule applied to the OUT list rather than to the IN list — the same rule, on the half nobody reads it against.

Lesson recorded alongside this bug.

Evidence

  • Read on origin/main @ 76b23fd (the design merge) and on parent/MOTIR-4054-talk-to-and-stop.
  • busy = state.phase === 'streaming'components/planning/PlanChangeRail.tsx:126; the disabled it produces on all three composer controls was confirmed by a headless render of the shipped component, not by reading the source.
  • search_work_items_semantic for the capability returns the STORY and the DESIGN as its top hits and no implementing child (coverage 1140/3973, so corroborating rather than conclusive; the four scope boundaries above are the direct evidence).