(motir-ai) Mirror the TERMINAL-card limb into `SHARED_PLANNING_RULES` — a `blocked_by` set is a function of the child set, not a snapshot
Repo: motir-ai. One PR. Type: content · Executor: coding_agent · blocked_by MOTIR-2917 (the motir-meta half — the written playbook lands first, so the two homes never disagree about the wording).
A standing planning rule has TWO homes (plan-rules/ ⟷ SHARED_PLANNING_RULES). MOTIR-2917 adds a sixth limb to core.md gate 8 — a TERMINAL card's blocked_by is a FUNCTION of its parent's child set, so FILING a sibling AMENDS it — and this card carries the same clause into the constant the shipped planner composes into every generation and every re-plan. Without it the hosted planner keeps filing siblings under a terminal card and wiring nothing, which is the defect MOTIR-2734 hit three runs running — and the hosted planner has no motir run guard behind it, so the run-time half of 2917 does not cover it.
The file, and the gap-vs-duplicate check (already run — this is a real gap)
SHARED_PLANNING_RULES is src/llm/planningRulePacks.ts (136 276 chars on origin/main, 34 named rule constants tagged by pack in CORPUS_ORDER, composed by composePlanningRules). Not src/llm/treeGeneration.ts — that only re-exports it now, and a grep there returns a clean, confident zero for this whole family (MOTIR-2663 sat open six days on exactly that false negative).
Probed on origin/main 2026-08-17, so a zero stands against a populated baseline:
| present | absent |
|---|---|
blocked_by 54 · sibling 27 · sweep 11 · ready: true 2 · TAKER 1 · SAME WRITE 1 | child set 0 · re-derive 0 · TERMINAL 0 · snapshot 0 · filed after 0 |
The target — ONE named constant, not an append to a blob
RECONCILE_EXISTING_NOT_DONE_WORK, tagged op-replan in CORPUS_ORDER — the constant carrying SWEEP FROM THE TAKER'S SEAT, NOT ONLY THE DONOR'S and NO TWO CARDS MAY OWN THE SAME WRITE (at char ~115 925). The new clause is that clause's mirror image and goes immediately after it. The two homes disagree about the PACK here and that is fine and deliberate — motir-meta files it under core.md gate 8, the mirror keeps it in op-replan; carry the WORDS, keep the mirror's placement, and do NOT re-pack as a side effect.
grep works in planningRulePacks.ts (~272 chars/line), unlike treeGeneration.ts; but a naive backtick scan mis-terminates because the rule text contains markdown code spans — extract to the backtick followed by ; / , / ).
The clause to add (match the mirror's uppercase-imperative register; do not paste Markdown)
AND THE SAME SWEEP RUNS DOWNWARD, TO THE CARD THAT MUST WAIT: A TERMINAL CARD'S
blocked_bySET IS A FUNCTION OF ITS PARENT'S CHILD SET, NOT A SNAPSHOT OF IT — SO FILING A SIBLING AMENDS IT. A card whose scope is "after all of X" — "runs LAST", "once every X has landed", or any criterion quantified over a WHOLE population (the full suite, every consumer, all callers) — was authored against the child set of ONE day, and every sibling filed afterwards silently falsifies it. Every other edge is a fact recorded once and then true; this one is a standing question, so the card most dependent on the plan being complete is the one whose dependency list is least likely to be. Spotting one is cheap: one read of the PARENT returns every child with its own blocked_by edges, so a card blocked by a large share of its siblings stands out in a single call. BUT READ THAT SHARE AS A TRIGGER, NEVER AS A FILTER — it is a floor the defect itself depresses, because the edges the card is missing are exactly the ones the ratio counts; the decisive evidence is the card's own scope sentence, which is stable and does not rot. So when you create a leaf under a container that already holds one, wire the terminal card blocked_by the new one as part of creation. THE OTHER DISPOSITION STAYS OPEN, BUT ONLY IN ONE FORM: AN EXCLUSION IS A SENTENCE ON THE TERMINAL CARD naming the sibling and the reason it cannot move the number — because the graph cannot hold one: an absent edge and a considered exclusion are the same absent edge, so SILENCE IS NOT AN EXCLUSION. And no sharpening of the missing-edge check reaches this family: that check scans a card's OWN description for not-done references, and a description cannot name a sibling that did not exist when it was written — the reference runs the other way.
Acceptance criteria
- FIRST, confirm MOTIR-2917's PR has merged to
motir-meta'smainand read the landed wording fromorigin/main:prompts/plan-rules/core.md(gate 8, the sixth limb); the clause added here is derived from THAT text, not from this card's draft, so the two homes cannot drift at birth. - The clause is appended to the
RECONCILE_EXISTING_NOT_DONE_WORKconstant insrc/llm/planningRulePacks.ts— not as a new constant, not in a different pack, and with no change to itsCORPUS_ORDERop-replantag — AFTER criterion 1's read. - The clause is written in the surrounding text's register (uppercase imperative, no Markdown tables, no
motir:chips), verified by reading the emitted string rather than the source line. tests/planningRulePacks.test.tsasserts the composed rule text carries the new clause for every legal cell that already includesRECONCILE_EXISTING_NOT_DONE_WORK— derive the cell list fromlegalPlanningRuleCells, do not hand-enumerate — asserting oncomposePlanningRulesoutput rather than on the constant, so a future re-partition that dropsop-replanfrom a cell fails loudly.- The share is NOT written into the mirror as a numeric threshold. MOTIR-2917's measurement is that "more than half its siblings" clears its own fixture (MOTIR-2734: 9 sibling blockers of 22, 41 %), because the missing edges are what the ratio counts. A mirror that ships the number the motir-meta half deliberately dropped would hand the hosted planner a test that fails open.
pnpm lint/pnpm typecheck/ the changed spec file pass locally (changed files only — the PR's CI runs the suite); the PR body quotes the composed-length delta and names MOTIR-2917's merged PR.- The PR body states that the RUN-time half has no mirror — it is
run.mdguard #4, a runbook for our own sessions — so the next reader does not go looking for it, and understands that the hosted planner's only protection against this family is the FILE-time clause this card lands.
Context refs
motir-ai/src/llm/planningRulePacks.ts— the mirror home;RECONCILE_EXISTING_NOT_DONE_WORKis the only constant this card edits.tests/planningRulePacks.test.tsis the spec.src/llm/treeGeneration.tsre-exports the composition only — the old path still RESOLVES, which is why a stale citation manufactures a false absence.- MOTIR-2917 — the
motir-metahalf, whose landed text is this card's input; its run comment carries the measurement behind criterion 5. - MOTIR-2734 / MOTIR-2832 — the fixture: the terminal card and the story whose child set kept growing.
notes.html#293 (motir-meta) — the lesson. - MOTIR-2914 and MOTIR-2879 — the sibling mirror cards, same file, same constant for 2914. Coordinate merge order with them if any two are open; two cards appending to
planningRulePacks.tsis the one real collision in this set.