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

Planning bug: a TERMINAL card's blocked_by set is written once and never re-derived, so every sibling filed after it leaves the card reading `ready: true` while definitionally un-runnable

Done
Description

Repo: motir-meta. Filed by the motir run MOTIR-2734 of 2026-08-17 — the third consecutive run of that card to stop before opening a PR, each time for the same structural reason and each time discovering it by hand.

The defect

MOTIR-2734 is a TERMINAL card: its own body says it "runs LAST", and its explanation says "flipping the default while any one of them is outstanding turns a green suite red." Its blocked_by set was written when it was authored — the twenty batch cards plus two application-layer cards — and has been amended only by the runs that tripped over it.

Its parent story MOTIR-2832 has since gained siblings continuously, because the story's own method is measure the residual, carve a card per class. On 2026-08-17 alone, three arrived — MOTIR-2887, MOTIR-2910, MOTIR-2911 — and not one carried a blocked_by edge to the terminal card whose acceptance criterion its failures falsify. So at the moment this run claimed it:

  • get_work_itemreadiness: { ready: true, openBlockers: [] }
  • validate_work_itemvalid: true, blockers: [], and two advisory entries that both point DOWNSTREAM (MOTIR-2515) or at an ARCHIVED predecessor (MOTIR-2528) — nothing naming 2887 / 2910 / 2911

Every readiness signal read green. Measured on the branch in post-cutover mode: 21 failures across four files, none of them this card's.

Why the existing machinery could not catch it

This is NOT the likely-missing-edge advisory's family, and that is the point. That channel scans a card's OWN description for references to not-done work items. 2734's description cannot name 2910 or 2911 — they did not exist when it was written, and the reference runs the other way: the NEW card is the one that should have named the terminal card. A scan of the referrer's text can only ever find edges the author already half-wrote.

Nor is it MOTIR-2903's shape (a card left todo after its substrate shipped) — the mirror case. Here the substrate never shipped and the card read ready anyway.

The rule this wants

A card whose scope is defined as after all of X has a blocked_by set that is a FUNCTION of its parent's child set, not a snapshot of it. Two places it can be enforced, and they are complementary:

  1. At FILE time (the cheap half). A new leaf created under a container that already holds a terminal card wires blocked_by from that terminal card to itself as part of creation. This is the sweep-the-referrers corollary applied DOWNWARD — to the card that must wait — rather than upward to the cards that referenced it.
  2. At RUN time (the backstop). motir run on a terminal card re-derives its blocked_by set from the parent's CURRENT child set before trusting ready: true. Any not-done sibling absent from the set is either a missing edge or a deliberate exclusion the run must state.

The discriminator is cheap and needs no heuristic about "terminal": a card blocked_by more than half its siblings is one.

Acceptance criteria

  • A rule in plan-rules/ states that a terminal card's blocked_by is re-derived from its parent's child set, naming both the file-time and run-time halves, with 2734 / 2887 / 2910 / 2911 as the fixture.
  • run.md's guard #4 gains the re-derivation check, stated so it fires on ready: true rather than only on an advisory — the advisory channel is structurally unable to see this family, and the guard currently opens by reading it.
  • The rule says what a DELIBERATE exclusion looks like on the record, so "this sibling genuinely does not gate me" stays expressible.

Context refs

  • MOTIR-2734 — the card, its three run comments, and the five → nine → twelve reader-set amendment trail.
  • MOTIR-2832 — the parent story whose child set keeps growing.
  • MOTIR-2903 — the mirror case, for the discriminator.
  • motir-meta/prompts/run.md — guard #4 and its advisory sub-rule; plan-rules/op-replan.md — the referrer sweeps.