Planning bug: run.md says a card at `todo` is structurally safe from a PR naming it — the sync WALKS the hops, and a one-criterion PR closed a four-criterion card
Planner telemetry, filed into the planner-bug home. It blocks nothing and is in no sprint.
Discovered in
motir run MOTIR-3264 close-out, 2026-08-23, when MOTIR-3401 was found done with three of its four acceptance criteria unstarted. Reset to To Do; the evidence is in the run comment on that card.
The defect — a corpus rule that is FALSE, in the direction that loses work
run.md's PR-title rule warns that a pull request carrying a card's key closes that card, and names the specific hazard: "that card is closed by its OWN code PR, and a lesson carrying its id would flip it Done first." It then argues the hazard did not actually fire in the 2026-07-04 incident, and generalises:
"It was not luck and it was not a near-miss: those cards sat at
todo, and the default workflow has notodo → in_reviewand notodo → doneedge, so no transition was ever legal — the same no-op every time, for a structural reason."
That reasoning is wrong. The sync does not require a single legal edge from the card's current status to the target; it walks the legal hops. Observed on MOTIR-3401, which sat at todo when its pull request opened:
20:13:04 To Do → In Progress
20:13:11 In Progress → In Review (motir-ai#285 opened)
20:31:40 In Review → Done (motir-ai#285 merged)
So the absence of a todo → done edge protects nothing, and a card at todo is not safe from a pull request that names it. The rule's own hazard paragraph was right and its reassurance paragraph is what a reader carries away — I read it, repeated it in writing on the card, and the card closed anyway eighteen minutes later.
The second, independent half: ONE criterion is not the card
Even with the mechanism understood, the shape that caused this is worth stating on its own. MOTIR-3401 is a planning bug whose fix is deliberately split across two repositories: criterion 3 is a lesson row in motir-ai, criteria 1, 2 and 4 are plan-rules/ changes in motir-meta. The motir-ai pull request delivered exactly one of the four and carried the key, because the PR-title rule says a code repo's pull request always carries it.
A pull request that delivers a PROPER SUBSET of a card's criteria must not carry that card's key — the sync has no notion of partial completion, and the completion gate that does (the repository-set gate, which holds a card until every repository's pull request merges) only engages when the card declares the set. MOTIR-3401 declared no targetRepos, so nothing held it.
Acceptance criteria
run.md's PR-title rule loses the structural-safety argument. The paragraph beginning "It was not luck and it was not a near-miss" is corrected on the record — not deleted — with the transition trail above as the falsifying evidence, and its conclusion reversed: a card attodoIS closed by a pull request naming it, because the sync walks the hops.- The rule states the SUBSET case positively: a pull request carrying a card's key asserts it completes that card. Where the card's criteria are split across repositories, either declare
targetReposso the completion gate holds it, or carry the key only on the pull request that finishes the card and reference the card in the body of the others — then close by hand (the drive-by rule already describes that mechanic). - The planning-bug shape is called out by name, because it is the recurring carrier: a planning bug's fix is routinely a lesson row in
motir-aiplus a rule change inmotir-meta, which is a two-repository card every time. The rule says so, so the next one declares the set instead of discovering this. - Verified against the shipped sync rather than argued. Whatever the rule ends up saying about which transitions fire, it cites
changeRequestStatusSyncas read onorigin/main, or a transition trail, not a derivation from the workflow's edge list — the derivation is exactly what failed here.
Context refs
- MOTIR-3401 — the card closed early; its reopen comment carries the trail.
- motir-ai#285 — the pull request that closed it, delivering one of four criteria.
motir-meta/prompts/run.md— the PR-title ↔ status-sync rule and its 2026-07-04 re-read, the text criterion 1 corrects.motir-corelib/services/changeRequestStatusSync.ts— the sync itself; criterion 4's source of truth.- MOTIR-1604 is NOT the mechanism here — its
deferred_open_prcounts open linked pull requests and correctly held MOTIR-3264 across two repositories on this same day. Deliberately not cited as the fix: it protects a declared multi-repository card, and MOTIR-3401 declared none. Said rather than left silent.