Implemented
The planning rule packs, re-cut on a phase → kind | type selector — and `type` becomes an output of SKELETON
Storyopened by Zhu YueMOTIR-3891
A total re-cut of the planning rule corpus and its selector. Three incremental cards (MOTIR-3853, MOTIR-3866, MOTIR-3869) improved the existing shape and, between them, established that the shape itself is wrong. This story replaces it.
The model, as decided
typeis an output ofskeleton, notdeepen. Todaypropose_nodecarries notypeanddeepen_nodesets it, so on a fresh plan the selector reads a field the skeleton never wrote — thetypeaxis selects nothing that a plan pass can act on.- Rule packs are selected by PHASE first —
skeletonordeepen. - At
skeleton, packs are selected by KIND. Nothing else. - At
deepen, packs are selected by kind OR type — never a cross-product of the two.- deepen
epic/story/bug⇒ no type; select by KIND. - deepen
task/subtask⇒ the type is set; select by TYPE.
- deepen
Point 4 moves bug out of the typed set for rule-selection purposes. It is in TYPED_KINDS today alongside task and subtask.
Why the current shape cannot be patched further
- The cell space is a cross-product it should never have been.
legalPlanningRuleCells()enumerates kind × type at deepen; under the model above a deepen cell is either a kind cell or a type cell, so the space is a sum, not a product. - A pack per type cannot express what a type needs.
VERIFY_EVERY_PRECONDITIONreaches every deepen cell and tells atranslatecard to runpg_policies,pg_roles,information_schemaandrow_security_active(). Subject mentions across that one constant: HTTP seam 24, design asset 23, graph 16, datastore 11, test lane 9. MOTIR-3856 tried to fix this by authoring a precondition rule per type; the PR was closed, because adding rules does not stop the wrong ones being delivered. - A LINE is currently a RULE, and that blocks every re-cut.
tests/treeGeneration.test.ts'sclauseOfstates it: "clauses are one line each in the constant", and a family of guards asserts specific limbs sit adjacent to named neighbours because each reads back to the one before it. Splitting a constant changes what counts as a rule. Conservation cannot see it — it compares words and length, and a space becoming a newline changes neither.
That last point is the real blocker and it is a DECISION, not an implementation detail: it changes a recorded invariant, so it is settled on its own card before any text moves.
Acceptance criteria
- A planning pass at
skeletonreceives the packs its KIND selects and no type pack at all; a pass atdeepenreceives the packs its kind selects (epic/story/bug) or its type selects (task/subtask), and never both. typeis set atskeletonand is an input todeepen, so a fresh plan's deepen pass composes the type's packs. Proven end-to-end on a generation pass, not only on the resolver.- No rule stops firing: for every clause that moves, the routing baseline shows the set of cells carrying it is a superset of the cells where its situation can occur.
- The corpus a
translate,copyorlegalcard receives contains no datastore, HTTP-seam or design-asset discharge — asserted, not reviewed by eye. - The worst cell and the corpus total are both measured before and after over the new cell space, at the run's own ref, and stated in the PR.
motir-meta's pack tree carries the same selector and the same cuts, and its MANIFEST is regenerated rather than hand-edited.
Context refs
motir-aisrc/llm/planningRulePacks.ts—resolvePlanningRulePacks,legalPlanningRuleCells,PACKS_BY_TYPE,CORPUS_ORDER.motir-aisrc/llm/workItemTypes.ts—TYPED_KINDS(task,bug,subtask),CONTAINER_KINDS.motir-aisrc/llm/treeGeneration.ts—propose_node/deepen_nodetool schemas,deepenSelectorFor,buildGenerationSystemPrompt.motir-aitests/treeGeneration.test.ts—clauseOfand the limb-adjacency guards.motir-metaprompts/plan-rules/split.py+DECISION.numbers.py— the generated MANIFEST and its pre-split row model.- MOTIR-3853 / MOTIR-3866 / MOTIR-3869 — the three landed cards this replaces the shape of; motir-ai#325 carries them.
- MOTIR-3856 — closed unmerged (motir-ai#332); its finding is folded in above.
Comments (0)
No comments yet — be the first to weigh in.