Three planning rules have no counterpart in `SHARED_PLANNING_RULES` — cardinality, the repeat-defect trigger, the suppressor limb
Repo: motir-ai. One PR. Surfaced while running MOTIR-2642, which read SHARED_PLANNING_RULES to check whether the compression it decides owes a mirror edit. It does not — but the read found a different gap, logged here rather than absorbed (notes.html #27).
✅ VERIFIED MOOT AND CLOSED — 2026-08-17
All three rules are now present in the mirror. Re-measured on
origin/maintoday, in the file the constant actually lives in:
rule probe result CARDINALITY cardinality4 — incl. "AND CARDINALITY IS AN ASSUMPTION TOO — EVERYTHING ABOVE ASKS 'DOES THIS EXIST?' AND NOTHING ABOVE ASKS 'HOW MANY ARE THERE?', SO A COUNT WRITTEN AS A SINGULAR NOUN SLIPS PAST EVERY ONE", plus "THREE CHECKS SETTLE A CARDINALITY QUESTION" and the repo-role standing instance THE REPEAT-DEFECT TRIGGER repeat-defect1 — "THE TELL YOU ARE ABOUT TO SKIP IT: the bug in front of you is well-diagnosed … AND THE COUNT IS A READ OF THE PLAN TREE YOU WERE HANDED" THE SUPPRESSOR suppressor·abandoned path4 · 3 — "THE ONE ELEMENT THE FOUR LIMBS CANNOT REACH — THE SUPPRESSOR: SORT THE ENUMERATION BY WHAT EACH ELEMENT'S ABSENCE DOES", sitting directly under "REMOVE THE CLIENT FIRST, THEN THE SERVER" Criterion 2 was honoured as well as criterion 1: each rule sits beside the sibling material this card named — cardinality beside the existence/precondition guidance, the repeat-defect trigger beside the bug guidance, the suppressor beside the abandoned-path enumeration. Criterion 3's probe sets all return non-zero. Nothing is owed; the card is closed without a PR.
Why it read as open for six days, and this is the part worth keeping. The measurement below was taken against
motir-ai/src/llm/treeGeneration.ts, which is where the constant lived on 2026-08-11. MOTIR-2624 moved it that same day (78b4e6d) intosrc/llm/planningRulePacks.ts, leaving behindexport { SHARED_PLANNING_RULES } from './planningRulePacks.js';— so the old path still resolves and shows no rule text. Anyone re-running this card's probes at the cited location would have confirmed all three zeros and concluded the gap was still open. A stale pointer that RESOLVES manufactures a false absence, and this card is the fixture for it. Swept across the corpus in motir-meta PR #197.
A standing planning RULE has two homes: motir-meta/prompts/plan-rules/ (the manual planner) and
SHARED_PLANNING_RULES in motir-ai/src/llm/treeGeneration.tsSHARED_PLANNING_RULES, defined in
motir-ai/src/llm/planningRulePacks.ts and re-exported from treeGeneration.ts (the shipped planner,
composed by both fresh generation and re-planning). A rule missing from the second is missing from every
plan the product generates.
The measurement
Probed against origin/main (grep returns nothing in this file — the lines are thousands of characters long; count substrings in Python):
| rule | home 1 | probes against the constant | result |
|---|---|---|---|
| CARDINALITY — "how many can there be, and what decides that?"; a count written as a singular noun is an assumption that passes every existence check | core.md gate 3 + the rule at line 504 | cardinality · how many can there be · one repo per project · degenerate case | all 0 |
| THE REPEAT-DEFECT TRIGGER — count the bugs under the story; the Nth is a signal about the design, not another bug | kind-bug.md | repeat-defect · count the bugs · third bug · recurring defect | all 0 |
| THE SUPPRESSOR — sort a migration's enumeration by what each element's ABSENCE does | type-migration.md | suppressor · absence does · abandoned path · call site | all 0 |
Two of the three sit in core.md, which every planning pass of every phase and kind loads — so the manual planner applies them universally and the shipped planner never applies them at all.
A control was run, because an absence proved by a probe list is only as good as the probes: ONE SUBTASK = ONE REPO = ONE PR came back 0 on its literal form and present on one repo / same repo / straddl / two repos — the constant carries it in different words. The three above survived every phrasing tried.
Acceptance criteria
SHARED_PLANNING_RULEScarries the cardinality rule, the repeat-defect trigger and the suppressor limb, each lifted from itsmotir-metawording rather than re-derived, in the constant's own register (imperative, no card keys, no dates — the constant carries no warrant and must not acquire any).- Each is inserted beside the sibling material the constant already carries, not appended at the end: the cardinality rule beside the existing precondition/assumption guidance, the repeat-defect trigger beside the bug-parenting guidance, the suppressor beside the abandoned-path enumeration.
- The three probe sets in the table above return non-zero against the constant after the change, by the same Python substring count (
grepcannot read this file). - The existing
JobKind/ prompt-contract guard tests still pass, and any test that pins the constant's shape is updated in the same PR. - No rule text in
motir-metais edited — this card is the second home only.
Context refs
motir-ai/src/llm/treeGeneration.ts—SHARED_PLANNING_RULES, andbuildGenerationSystemPromptwhich concatenates it.motir-ai/src/jobs/handlers/replan.ts— the second consumer, so a gap here reaches re-planning too.motir-meta/prompts/plan-rules/core.md(gate 3 + the cardinality rule) ·kind-bug.md·type-migration.md— the wording to lift.