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-2905

Planning bug: a card that NAMED its own blocker in prose and NAMED its own open decisions still shipped with no `blocked_by` edge and an acceptance criterion nobody could evaluate — the diagnosis was right and none of it was wired

Done
Description

Filed by: motir run MOTIR-2761 (2026-08-17), run.md guards #4 + #5. About: MOTIR-2761. Correction already applied — this is the telemetry record, not scheduled work.

What went wrong

MOTIR-2761 was authored 2026-08-12 as a well-diagnosed bug: a four-row evidence table, a named root cause, a fix direction with file paths. It read ready: true, openBlockers: [], validate_work_itemvalid: true. It was not runnable, for two independent reasons the card itself had already written down in prose.

1. It named its own blocker and never wired it. The § Related section says of the sibling defect MOTIR-2758: "Two defects, both on the predicate set of the same two reads — worth fixing in one pass, and worth reading together before the fix is planned." That is a dependency stated in words. blockedBy was []. By the time the card was claimed, MOTIR-2758 was in_review on open PR #2083, which:

  • renames browsableProjectIdsbrowsableProjectScopes and changes all four Home reads from projectIds: string[] to HomeProjectScope[];
  • touches five of the six files MOTIR-2761 must edit, including +145 lines in tests/integration/home/personal-reads.test.ts.

So MOTIR-2761's fix direction — "The repository layer needs no change … already accept projectIds … pass [activeProject.id]" — was already false on an open branch. A run that trusted ready: true would have branched off origin/main and rebuilt the sibling's half: two PRs each green alone, composing badly (notes.html — the fixes cancel on merge family).

2. It named its own open decisions and then wrote one into an acceptance criterion. The card carries a section headed "Two open decisions the fix card must carry (Yue's, not the implementer's)", and then AC 5 reads "The no-project state resolves per the decision above". A criterion that defers to a decision the same card declares is not the implementer's cannot be evaluated by whoever claims the card — it is a placeholder wearing a checkbox. The card also called itself "a fix subtask, not this card" while carrying type: code, targetRepo: motir-core, 5 points and a full AC set: it was both the record and the fix and had not decided which.

The common shape (why these are one bug, not two)

Both halves are the same failure mode: a correct observation written as PROSE instead of as STRUCTURE. The card knew about its blocker and knew about its unmade decisions. Neither fact reached a field any tool reads — not blocked_by, not a decision card, not the status. Readiness is computed from edges, so a dependency that exists only in a paragraph makes a card look more ready than one that admits it, and an open decision recorded only in prose makes an AC look complete. The planner's own prose is not a channel; only the graph is.

validate_work_item's advisory channel did fire — {referenced: MOTIR-2758, referencedStatus: in_review, severity: advisory} — at the correct tier, naming the correct blocker. Severity was advisory rather than likely-missing-edge only because the reference sat in § Related rather than inside the acceptance criteria. It changed nothing, because nothing between authoring and dispatch read it. Same shape as MOTIR-2075.

Fix applied / Resolution taken

  • link_work_itemsMOTIR-2761 blocked_by MOTIR-2758 (the edge the author owed).
  • create_work_itemMOTIR-2904, the type: decision card carrying both open decisions (the no-project state + post-auth landing; whether a cross-project "my work" survives), executor: coding_agent, deliverable docs/decisions/home-scope.md. link_work_itemsMOTIR-2761 blocked_by it.
  • update_work_itemMOTIR-2761 amended IN PLACE (never cancel-and-recreate): a BLOCKED block naming both blockers and the run order; fix-direction step 2 corrected against the #2083 branch with the real HomeProjectScope shape; the "a fix subtask, not this card" contradiction retired; AC 5 re-pointed at the decision RECORD; a new AC added so the lifecycle predicate #2083 introduces is not silently dropped when the project axis narrows.
  • transition_statusMOTIR-2761Blocked.
  • notes.html lesson appended in motir-meta (the LESSONS corpus; this card is the CARD half).

No sprintMOTIR-1465 carries none, MOTIR-2761 is itself in the backlog, and there is no active sprint in the project.

Lesson

A card that can articulate its own blocker or its own open decision has done the hard part and must not stop there — the sentence is the trigger to write the edge. Concretely, at authoring time: grep the finished card body for a sibling MOTIR-<n> that is not done and not in blockedBy, and for any phrase of the "X must decide" / "open decision" / "per the decision above" family. The first is a missing edge; the second is a missing decision card plus an AC that is not yet a criterion. Both are cheap to fix while writing and expensive at dispatch — this one cost a full claim-and-stop and left a stale fix direction on the card for five days.

Related

  • MOTIR-2761 — the card this is about · MOTIR-2904 — the decision card carved out of it
  • MOTIR-2758 / MOTIR-2759 — the sibling defect and ITS planning-bug record. 2759 was about an AC leaving an AXIS unbounded on the same two reads; this one is about the same authoring pass failing to wire what it had already seen. Third occurrence on this surface trips plan-rules/kind-bug.md § the repeat-defect trigger.