Planning bug: a criterion named a consumer that was PRESENT but UNREACHABLE — `situations/replan.ts`'s partition had been dead since MOTIR-3978
Found running MOTIR-4160 (relates_to). The card shipped complete; nothing is blocked. This is telemetry about the PLAN.
What the plan said
MOTIR-4160's second acceptance criterion:
"Both partitions (
planningTarget.ts,situations/replan.ts) and the(IMMUTABLE)grounding annotation read the project's terminal set from the boundary."
What was true
situations/replan.ts's partition was unreachable code. MOTIR-3978 deleted that situation's grounding READER; toExistingItem, partitionSubtree, buildReplanGrounding and describeReplanContext were left behind unexported and uncalled. The only symbols any module took from that file were REPLAN_SITUATION_PARTS / REPLAN_SITUATION_PROMPT:
$ git grep -an "situations/replan" origin/main -- src tests
src/jobs/handlers/plan.ts:10: import { REPLAN_SITUATION_PARTS } …
tests/framingTiers.test.ts:30 · tests/onboardingIsAFactAboutTheTree.test.ts:27
tests/sessionPromptGate.test.ts:68 · tests/situationPromptPhaseSplit.test.ts:20
So the criterion asked the run to wire a network read into code with no caller — which would also have left standing the "second notion of terminal beside the real one" the card's FIRST criterion forbids. The two criteria contradicted each other, and only one of them could be satisfied.
Why the authoring pass could not see it
The file said so and the reader was looking at the wrong end of it. replan.ts carried, at its foot, a comment stating outright "THE READER IS GONE (MOTIR-3978), AND SO IS THE HANDLER BEFORE IT … the partition is not gone: it is computed for EVERY target now (jobs/planningTarget.ts)". The authoring pass read the file at the partition's own line range (the card's context refs cite replan.ts:163-178, exactly the dead function), where a well-commented, correct-looking partition sits — and a partition that is literally there, with a TODO on it naming the fix, reads as a live consumer.
The general shape: a card enumerating the consumers of a symbol it retires is enumerating call sites, and a call site is a reachability question, not a text-search one. git grep <symbol> answers where does this name appear; the criterion needs what still runs. The two agree everywhere except on dead code — which is exactly where a retirement card looks.
What would have caught it
For each consumer a retirement card names, one question before it becomes a criterion: is this consumer reachable — is its enclosing function exported, and does anything import it? One git grep -an "<module path>" for the module's importers answers it, and it is the same command that later produced the evidence above.
Disposition on the card
Amended on the record in a comment on MOTIR-4160 and in motir-ai#379's body; the criterion is satisfied by DELETING the dead partition rather than wiring it. The card body is left as authored so a reviewer sees both what was asked and what was delivered.
Acceptance criteria
- The reachability check above is added to the retirement/consumer-enumeration guidance in
motir-meta/prompts/plan-rules/(the pack that carries precondition-verification / the enumeration limb) — as an ADDITION, never a re-wording of an existing rule. - It states the DISCRIMINATOR: a consumer list is a reachability claim, and
git grep <symbol>cannot settle one — the importers of the enclosing module can. - Cites this bug and MOTIR-4160 as the fixture.