Planning bug: a mirrored constant MOVED and nothing swept the referrers — and the stale pointer RESOLVES, so it manufactures a false absence
TWO PRs, one card — motir-meta #197 (the corpus) and motir-core #2072 (one ADR reference). Both carry this key in their titles, so the sync defers on the first merge and closes the card on the last (MOTIR-1604). Both are already open, which is the one precondition that defer needs.
Found on 2026-08-17 when Yue asked whether the motir-ai mirror actually carries the rules MOTIR-2879 proposes to widen. It does. The card asking was pointed at a file that no longer holds them.
The defect
MOTIR-2624 moved SHARED_PLANNING_RULES on 2026-08-11 (78b4e6d, the mirror's own pack split) from motir-ai/src/llm/treeGeneration.ts into src/llm/planningRulePacks.ts — ~32 named rule constants, each tagged with its pack in CORPUS_ORDER, with the constant now derived as a composition over all of them. Nothing swept the referrers. Six days later four live citations in plan-rules/ still sent a reader to the old file, and so did a motir-core ADR.
plan-rules/op-replan.md already carries the rule that was missed — sweep the REFERRERS on any re-scope — and DECISION.md itself even predicted the move it then failed to follow up: its "For MOTIR-2624" section said "SHARED_PLANNING_RULES is today a single exported constant", a sentence written to be falsified by the card it was addressed to.
Why this stale pointer is worse than the ordinary kind: it RESOLVES
treeGeneration.ts still carries export { SHARED_PLANNING_RULES } from './planningRulePacks.js';. So a reader who follows the citation finds the symbol exported and no rule text — and the cheapest conclusion available is "the mirror does not carry the rule I came to check."
That is a false ABSENCE, produced by a citation that looks like it checked out. The corpus's own defence against a negative claim is re-run it and paste the count — and here re-running it at the cited location confirms the zero. The defence is defeated by being performed correctly.
What it cost, measured
- MOTIR-2663 — "Three planning rules have no counterpart in
SHARED_PLANNING_RULES— cardinality, the repeat-defect trigger, the suppressor limb",todo, open six days,motir-ai, 2 points. Re-measured in the file the constant actually lives in:cardinality4 ·repeat-defect1 ·suppressor4 /abandoned path3 — all three present, each beside the sibling material its own criterion 2 asked for. Its probes were run at the old path, so a runner picking it up would have confirmed the three zeros and rebuilt rules that already shipped. Closed as verified moot. - MOTIR-2879 — filed 2026-08-16 by the MOTIR-1465 sweep naming the old path as its edit site; amended on the record the next day.
- MOTIR-2732 — the same stale context ref, corrected.
Fix applied
- motir-meta PR #197 —
COMPRESSION.md(§ Context path struck through with a dated note that the READING stands; References corrected outright),DECISION.md("today a single exported constant" struck through and marked DISCHARGED; References corrected),CORPUS-MAINTENANCE.md(the gate-14 verification now namingAC_SATISFIABLE_INSIDE_THE_BOUNDARY, which carries all three axes today). - motir-core PR #2072 —
docs/decisions/project-repository-set.md's reference split in two, because both halves are real: rule text inplanningRulePacks.ts, prompt seam and proposal schema intreeGeneration.ts. notes.html#283 — the lesson, in PR #197.notes.htmlis otherwise untouched: its fourteen mentions were true when written and are historical records of readings taken at a time, not instructions anyone follows.
Acceptance criteria
- No live rule file, record or ADR in any repo cites
treeGeneration.tsas where the rules ARE. Every surviving mention says explicitly that it re-exports only, or dates itself as a reading taken before the split. - Every not-
donecard citing the old path is corrected;search_work_itemsfortreeGenerationreturns only cards whose mention is the corrected, deliberate form. - MOTIR-2663 is closed with its three probes re-run at the real path and their counts quoted.
notes.htmlcarries the lesson, and it is written about the resolving pointer, not about path hygiene in general — the transferable part is that a re-export makes a dead citation return a confirmable absence.- Both PRs carry this key in their titles so the last merge closes the card. Neither is merged before the other is open.
Context refs
motir-ai/src/llm/planningRulePacks.ts— where the constant lives;src/llm/treeGeneration.ts— the re-export.prompts/plan-rules/op-replan.md— the sweep-the-referrers rule this violates.- MOTIR-2624 (
78b4e6d, 2026-08-11) — the move. MOTIR-2663 — closed as moot by this finding. MOTIR-2879, MOTIR-2732 — corrected.