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

The `type` axis reaches only 4 of 14 types, and `phase-deepen` carries the other ten's rules — every deepen cell pays 78,304 chars it cannot all need

Done
Description

A corpus parity + routing audit of motir-ai's SHARED_PLANNING_RULES against motir-meta's prompts/plan-rules/ packs. Measured on origin/main at 4124dbe0 (motir-ai) and the motir-meta working tree, 2026-08-28.

The finding

1. The type axis is mostly unwired. PACKS_BY_TYPE in src/llm/planningRulePacks.ts maps 4 of the 14 typescode, design, chore, deploy. The other ten (test, content, research, verification, decision, manual, copy, translate, legal, review) resolve to no type pack at all, so replan/deepen/bug/test and replan/deepen/bug compose byte-identically at 163,195 chars — the test axis adds nothing.

2. phase-deepen is one indivisible pack loaded whole on every deepen cell. Measured over all 104 legal cells from legalPlanningRuleCells(): all 94 deepen cells load all 78,304 chars of phase-deepen39.0% of the corpus. resolvePlanningRulePacks only ever adds kind/type packs; it never subtracts. Worst cell replan/deepen/bug/code = 171,888 chars (85.6%); best cell plan/skeleton/epic = 53,221 (26.5%).

3. The type-specific rules are fused into phase-deepen and core, which is why they cannot be selected. VERIFY_EVERY_PRECONDITION is a single segment of 49,449 chars — 24.6% of the whole corpus — fusing ~30 distinct concerns (12 numbered limbs plus ~18 unnumbered AND … limbs). Text-probing shows it carries type-bars' GENERATED-OUTPUT rule, and core/CODING_CONVENTIONS_AND_ONE_REPO_ONE_PR carries type-test's scaffold/harness rules. Because the partition's unit is the SEGMENT, a 49KB segment can never be split off a cell.

4. Three motir-meta packs have no motir-ai counterparttype-bars, type-test, op-sprint (15 loadable packs vs 12). Most of their content was redistributed rather than dropped, but three rules are genuinely absent from motir-ai, and all three pass the rule test ("in situation X, do Y"):

  • type-test: the within-run vs cross-run dedup split — attribute each half to the code that enforces it, naming the function + persistence layer on origin/main.
  • type-bars: the classify-and-generalize gate — generalizability gate, generic rewrite, dedup, explicit disposition for every source entry.
  • type-bars: the research/spike bar — question, written deliverable, timebox.

5. What did NOT hold up: the demotion hypothesis. The incident-strip test over all 35 segments flags 47 sentences (5.5% of the corpus) as narrative-register. On reading, ~19 are genuinely retrospective — but every one is warrant attached to a live "do Y" one or two sentences away, which COMPRESSION.conserve.py exists to protect. Under MOTIR-3293's definition a rule keeps its warrant. Demotion is not the lever; selection is. Deleting that 5.5% would save ~11 KB and cost the reasons.

6. replan.ts bypasses selection entirelysrc/jobs/handlers/replan.ts:8 imports the flat SHARED_PLANNING_RULES re-exported from treeGeneration.js, so a replan pays 100% of the corpus regardless of cell.

For scale: motir-meta's worst cell is 75.9% of its corpus (2,817 of 3,712 lines); motir-ai's replan path is 100%. The corpus has gone 125,476 → 200,797 chars (+60%) since conservation was established, and phase-deepen.md in motir-meta has regrown 314 → 520 lines since MOTIR-3297 restated it.

Acceptance criteria

  • PACKS_BY_TYPE maps every one of the 14 WorkItemTypeName values, or the resolver names in a comment why a value legitimately takes no type pack; a guard asserts the map is TOTAL over the type enum so a new enum member cannot silently take none.
  • type-test and type-bars packs exist in CORPUS_ORDER and carry the three rules named in finding 4, mirrored from motir-meta prompts/plan-rules/type-test.md and type-bars.md.
  • The type-specific limbs currently fused into VERIFY_EVERY_PRECONDITION and CODING_CONVENTIONS_AND_ONE_REPO_ONE_PR are MOVED into the type packs that gate them, not copied — grep for the GENERATED-OUTPUT clause and the scaffold/harness clause returns exactly one segment each.
  • phase-deepen's share of the corpus falls, measured over legalPlanningRuleCells() at the run's own base with the ref quoted, and both the before and after per-cell figures are stated in the PR. Do not target the figures printed in this card — re-measure.
  • The conservation baseline and the register ceiling are refreshed in the same commit as the move, with each fixture's own diff reviewed in the PR; the cautionary count does not rise.
  • plannerPromptAssemblyGate.test.ts's no-orphan and REACHABILITY invariants still pass, and planningRuleRouting.test.ts proves each moved clause reaches its intended cells and no others.

Context refs

  • motir-ai src/llm/planningRulePacks.tsPACKS_BY_TYPE (~line 437), resolvePlanningRulePacks, legalPlanningRuleCells, CORPUS_ORDER, VERIFY_EVERY_PRECONDITION.
  • motir-ai src/jobs/handlers/replan.ts:8 — the flat-corpus import (finding 6).
  • motir-ai tests/planningRuleConservation.test.ts, tests/planningRuleRegister.test.ts, tests/plannerPromptAssemblyGate.test.ts — the three guards a move must clear.
  • motir-meta prompts/plan-rules/type-test.md, type-bars.md, op-sprint.md — the packs with no motir-ai counterpart.
  • motir-meta prompts/plan-rules/CORPUS-MAINTENANCE.md § RULES vs LESSONS — the routing definition, in a file no planning pass loads.
  • MOTIR-3293 / MOTIR-3297 — the restatement epic this audit re-measures.

⚠️ Over the estimation gate at 8 points. The three limbs — map the type axis, create the two packs, move the fused clauses — are separable and should be split into subtasks before dispatch; sized here as the SUM so the gate reads honestly.