Planning bug: a `blocked_by` wired to an ARCHIVED predecessor gates nothing — the card sealed `ready: true` against a retirement that has not shipped, and the advisory that named it was never read
Found by: motir run MOTIR-3819, 2026-08-28, at the dispatch guard — before any worktree existed. The card was NOT claimed.
The defect
MOTIR-3819 was created at 19:09:37Z with its blocked_by pointing at MOTIR-3785, and relates_to edges to MOTIR-3785 and MOTIR-3791. Both of those cards had been archived at 18:36:26Z — 31 minutes earlier — by the restructure that hoisted the CI-publisher retirement out of MOTIR-3780 into the new story MOTIR-3795. Their live successors, byte-identical in title and scope, are MOTIR-3797 and MOTIR-3800.
An edge to an archived item does not hold a card out of the ready set. So MOTIR-3819 sealed:
readiness: { ready: true, openBlockers: [], blockedByAncestor: null }
validate_work_item: { valid: true, blockers: [] }
…on a card whose own body says, in its own words, "this should not merge before it" and "fixing it early would make the panel lie in the other direction for as long as the lane still runs." Every automatic signal said start; the card's prose said stop; and the prose was right.
Evidence that the precondition has NOT shipped
Read on origin/main @ c4d11059f at dispatch:
$ git ls-tree -r origin/main --name-only | grep upload-design-assets
scripts/upload-design-assets.mjs
$ git show origin/main:.github/workflows/ci.yml | sed -n '490,521p'
- name: Publish the design result
...
node scripts/upload-design-assets.mjs
The CI publisher and its design-guards publish step are both live. MOTIR-3797 — which deletes them — is blocked, behind MOTIR-3796 (the deployed-tenant gate) at todo. So MOTIR-3819 is two hops from ready, and ready: true was off by two hops.
⚠️ The advisory channel DID fire. Nothing read it.
validate_work_item on MOTIR-3819 returns, and returned at file time:
{ item: MOTIR-3819, referenced: MOTIR-3785, referencedStatus: "blocked", severity: "advisory" }
{ item: MOTIR-3819, referenced: MOTIR-3791, referencedStatus: "blocked", severity: "advisory" }
Both entries name the right cards at the right tier. This is the same shape as run.md's canonical guard-#4 fixture — "the advisory fired at the right tier, naming the right blocker … it changed nothing because no step read it" — with one sharpening worth recording: the two entries are plain advisory, not likely-missing-edge, because from the detector's side the edge is not missing — it is present and it points at an archived card. A runner filtering on likely-missing-edge sees nothing here, which is exactly the narrow reading run.md already warns against.
Root cause — a snapshot, not a lookup
The filing run had just performed the restructure. It wrote MOTIR-3819's references from the tree as it stood when it started reasoning, not as it stood when it wrote. The archived keys were, half an hour earlier, the correct ones.
The general shape: a card authored after a re-plan cites the pre-re-plan keys, and the graph accepts it silently — because an edge to an archived item is well-formed, resolvable, and inert. An absent edge and an inert edge are indistinguishable from every readiness signal, and only the inert one looks like diligence.
Disposition applied in this run
All DIRECT, between cards that already exist — no plan proposal was needed, because nothing had to be created or re-scoped:
link_work_itemsMOTIR-3819blocked_byMOTIR-3797 (a sibling under the same parent MOTIR-3795, so gate 7 is satisfied and the edge belongs at the leaf).unlink_work_itemsthe deadblocked_byandrelates_toedges to the archived MOTIR-3785, and therelates_toto the archived MOTIR-3791.link_work_itemsMOTIR-3819relates_toMOTIR-3800.update_work_itemMOTIR-3819 — every reference rewritten to the live successor, with an amendment block on the record.transition_statusMOTIR-3819 → Blocked.
Acceptance criteria
- MOTIR-3819 is
blocked_byMOTIR-3797 and carries no edge to an archived item. (Landed in this run — closing this is a read.) - MOTIR-3819's body cites MOTIR-3797 / MOTIR-3800 and records the amendment. (Landed in this run — closing this is a read.)
- A LESSON is written to the store carrying the takeaway: after a re-plan that archives and re-creates a card, a later referrer must cite the LIVE successor — and at dispatch, a
blocked_bynaming an archived item is an UNMET precondition, never a satisfied one, because readiness cannot tell an inert edge from an absent one. Scope is GLOBAL by the strip-the-identifiers test: the takeaway survives removal of every repo, key, path and gate number. run.md's guard #4 advisory block gains the archived-referent limb: a plainadvisorynaming a not-donereference must be checked for whether the card's EDGE points at that same item in an archived state — the one case where an edge exists and gates nothing.- No product code. The advisory channel behaved correctly and the readiness rule is defensible on its own terms (archiving says do not work this, so keeping dependents blocked on it for ever would be worse). What failed is that nobody read the output.