Planning bug: the corpus CONTRADICTS ITSELF on what approve does to a proposal's status — `_shared.md` and `run.md` say it derives nothing and cite the code, `plan-procedure.md` says it derives from the edges, and the shipped `materialize` agrees with `plan-procedure.md`
Type · planning bug (a corpus FACT that is false, stated with a code citation and the word verified)
Parent · MOTIR-1465, the planner-bug home. Holds up nothing, joins no sprint.
Discovered in · the approval of the design-result plan (MOTIR-3780), by observing what the eleven materialized subtasks were actually born at.
The contradiction, in the corpus's own words
prompts/plan-procedure.md:453 — CORRECT:
"a proposal has no status, and approve seeds it from the
blockedByRefstheaddcarried — so getting the EDGES right IS setting the status"
prompts/_shared.md:171-172, _shared.md:516-517 and prompts/run.md:1500-1501 — FALSE, and each states it with a code citation:
"⚠️ AND KNOW WHAT APPROVE DOES NOT DO. A materialized
addtakes the workflow's INITIAL status; nothing reads its edges to seed Blocked (plansService.materializesetsstatus: statusKey— verified onorigin/main)."
Three sites say one thing, one says the opposite, and the majority is wrong.
What shipped reality does
lib/services/plansService.ts on origin/main has two passes, ~180 lines apart:
:1084 status: statusKey ← the initial status, at create. This is the line
the false claim was read off.
:1264 const unready = createdIds.filter(
(id) => !classifyBlockerReadiness(byItem.get(id) ?? [], terminalByProject).ready)
:1274 const blockedStatus = await workflowsRepository.findStatusByKey(… 'blocked' …)
:1299 await workItemRepository.update(id, { status: blockedStatus.key }, tx)
The second pass is guarded — it resolves the project's OWN blocked status rather than assuming one, and under a restricted workflow policy it requires the initial → blocked hop to be a declared transition. Either guard failing leaves the initial status in place, which is almost certainly the behaviour the false claim was generalised from.
Observed, on this project's own tree. MOTIR-3780 materialized eleven subtasks at 17:52:37:
| card | blockers | status at birth |
|---|---|---|
| MOTIR-3781 | none | todo |
| MOTIR-3782 … MOTIR-3791 | one or more not-done | blocked |
A blanket initial status would have made all eleven todo. The split is exactly the edge graph, so the derivation ran.
Root cause
A correct reading of ONE site, generalised into a claim about the mechanism — and then hardened by the words "verified on origin/main", which is what makes it expensive: a reader who does the right thing and trusts a cited, verified claim inherits the error, and the citation points at a real line that really does say status: statusKey.
This is the second instance of this exact shape recorded today — see MOTIR-3775, where a card's measurement block was impeccable and the causal sentence beside it was never checked. There the unit was a sentence next to a measurement; here it is a second pass 180 lines below the line that was read. The family is a verified reading of a part, asserted of the whole, and at two occurrences it is worth naming rather than re-diagnosing.
A likely history worth checking: MOTIR-3050 — "An approved plan's blocked cards land as todo — materialize never derives a status" — is done. So the claim was TRUE when written, was FIXED, and the corpus was never swept. If so this is also an instance of a fix that closes a card and leaves the prose that described the defect standing, which is worth a sentence in the correction.
Why it matters, given the ADVICE around it happens to survive
The guidance the false claim supports — "get the EDGES right; do not expect the status to follow" — is still good practice, so nothing built on it is wrong today. That is precisely why it has lasted. But the FACT is load-bearing in two ways:
- It invites redundant work. A planner who believes approve leaves every card
todomay plan a post-approval status sweep, or tell a reviewer the board will lie to them. Both are now false, and both cost. - It teaches a reader to distrust a mechanism that works.
_shared.mdis read by every command; a warning labelled ⚠️ and verified is the last thing anyone re-checks.
Acceptance criteria
- All three false sites are corrected —
prompts/_shared.md:171-172,prompts/_shared.md:516-517,prompts/run.md:1500-1501— to say that approve DOES deriveblockedfromblockedByRefs, naming the two-pass shape and both guards (the project must HAVE ablockedstatus, and underrestrictedtheinitial → blockedtransition must be declared). - The correction keeps the surviving advice, which is unchanged and still the point: get the EDGES right, because the edges are what the derivation reads.
plan-procedure.md:453is left alone — it was correct — and the correction CITES it, so a reader who met the old text can see which half won.- The corrections are ADDED with the old text marked, never silently re-worded (
motir-meta's standing convention): strike or ⚠️ CORRECTED with the date, so an existing citation still lands somewhere that explains what changed. - The evidence is on the record: the two line numbers in
plansService.ts, both guards, and the MOTIR-3780 materialization table above. - MOTIR-3050 is read and its relationship stated — if it is the fix that made the claim stale, say so, because "a
donefix leaves the prose describing the defect standing" is the reusable half. SHARED_PLANNING_RULESneeds NO sibling card — verified:git grep -in 'INITIAL status|seed Blocked|materialize.*status'overmotir-ai origin/main -- src/returns only unrelatedblockedByRefsplumbing incoreClient.tsand the job handlers. Gate 19 is discharged by that grep, quoted in the pull request.
Context refs
motir-meta/prompts/_shared.md— the two false sites.motir-meta/prompts/run.md— the third.motir-meta/prompts/plan-procedure.md— the correct site, to cite rather than change.motir-core/lib/services/plansService.ts—:1084(the line that was read) and:1264–:1302(the pass that was not).- MOTIR-3780 — the materialization this was observed on.
- MOTIR-3050 — the probable origin of the staleness.
- MOTIR-3775 — same family, filed earlier today.
Resolution
(open)
Comments (0)
No comments yet — be the first to weigh in.