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 · Roadmap

MOTIR-3804Done

(motir-core) A `modify` proposal's body cannot carry an intra-plan CHIP — materialize rewrites `motir-ref:planItem:` on `add`s only, so an amendment naming a card the same plan proposes ships an inert link

Opened by Zhu Yue ·

Repo · motir-core. Found on 2026-08-28 while authoring the to-do-list plan (cmtdaoakn01fehvphc5q6s0dh), which modifys MOTIR-1344 to name a story the SAME plan proposes.

The defect

plansService.materialize's Pass 3 rewrites intra-plan item-link tokens — [label](motir-ref:planItem:<id>)[label](motir:<workItemId>) — inside

for (const { created, prefix } of createdAdds) { … rewriteIntraPlanRefs(created.descriptionMd …) … }

createdAdds holds add proposals only. A modify proposal's patch.descriptionMd / patch.explanationMd are applied to their target and never passed through rewriteIntraPlanRefs — verified at origin/main 268bb2a5b: git grep -n 'rewriteIntraPlanRefs' -- lib/services/plansService.ts returns exactly two call sites (lines 1325 and 1333), both inside that loop.

So a token in a modify body materializes verbatim, as a literal motir-ref:planItem:<id> href pointing at nothing. It does not chip, it does not resolve, and — unlike an add's dangling ref — it does not even reach the console.warn that reports one, because the rewrite never runs on it.

Why this is a PLANNING defect and not a niche one

It is the shape a re-plan takes by default. plan-procedure.md step 4 tells an author to "write every reference to another work item as an ITEM LINK, never a pure-text key", and to use motir-ref:planItem:<tempRef> for "an intra-plan sibling the generator is still proposing" — while THE REPLAN ACTION's own three ops are add the new, remove the superseded, and modify the survivor. Amending a survivor to name the card that took over part of its scope is the single most common thing a re-plan writes, and it is exactly the case the rewrite cannot reach.

The failure is silent in the worst direction. An author following the rule produces a broken link; an author who notices produces a prose reference and quietly violates the rule. This pass took the second road: MOTIR-1344's 2026-08-28 amendment names the new to-do-list story descriptively ("the sibling story this card is blocked_by") rather than as a chip, and says so in the body. That works and it is worse than a chip.

Fix direction

Run the same rewrite over a modify's patched bodies. The information is all present at Pass 3 — planItemToWorkItem is already built and already covers every add in the plan — so this is a second, small loop over the modifies whose patch carried a body, applying rewriteIntraPlanRefs to descriptionMd and explanationMd and surfacing an unresolved ref through the same console.warn. Consider whether autoRelateWorkItemMentions should run on a modified body too, or whether that would re-wire edges on a card the plan only meant to amend — decide it, do not leave it implicit.

Acceptance criteria

  1. A modify proposal whose patch.descriptionMd carries [label](motir-ref:planItem:<id>), where <id> is an add on the same plan, materializes with that token rewritten to [label](motir:<the created work item's id>) — asserted end to end through approvePlan, not on the helper.
  2. The same holds for patch.explanationMd.
  3. An unresolvable planItem: ref in a modify body is left inert and reported through the same console.warn path an add's dangling ref uses — asserted, so the two ops fail the same way.
  4. A modify body containing no such token is byte-identical after materialize (no incidental rewriting).
  5. Whether autoRelateWorkItemMentions runs over a rewritten modify body is decided and asserted — either it does and the relates_to edges appear, or it does not and a test says so. Not left to inference.
  6. git grep -n 'rewriteIntraPlanRefs' -- lib/services/plansService.ts shows the call sites covering both ops, and plansService's coverage stays at or above the per-file floor.

Context refs

  • lib/services/plansService.ts ~1315–1360 — Pass 3, the createdAdds loop, and the console.warn for a dangling ref.
  • lib/mentions/workItemRefs.tsINTRA_PLAN_REF_TOKEN_RE and rewriteIntraPlanRefs; the token form is [label](motir-ref:planItem:<planItemId>).
  • lib/dto/plans.ts:130 — the contract line promising motir:<id> / motir-ref:<tempRef> are "resolved at materialize", which is true of one op and not the other.
  • MOTIR-1344 — the card whose 2026-08-28 amendment had to fall back to a prose reference because of this.
  • MOTIR-3111 — the sibling defect in the same family: PlanItemPatch omitted explanationMd entirely, which made the FIELD unsettable on a modify. This one makes that field's CONTENT unresolvable. Same op, same blind spot, one layer apart.

Discussion

No comments yet.

Adding to this discussion signs you in on app.motir.co and brings you back to this request.

Add a comment