MOTIR-3921Done
The story’s gate — what each PHASE’s cell can discharge, end to end from a real pass
The per-repo gate for motir-ai, run after this story's code cards merge. It asserts the property none of them can assert alone, because each owns one tier of a split that is only correct as a whole.
What it asserts that its producers cannot
- THE ACT TEST, MECHANISED, OVER EVERY CELL. For each of the 17 deepen cells, the composed text contains no rule whose discharge needs a tool absent from
DEEPEN_PHASE_TOOLS; for each of the 5 skeleton cells, the same in reverse for deepen-only acts. The producers each move their own tier and can each be right while the assembled cell still carries a stray rule from the other. - END TO END, ON THE REAL PROMPT. Drive
runGenerationPassand read the system message a DEEPEN session was actually sent — framing INCLUDED, which is the half the pack-level guards structurally cannot see. That message contains no skeleton framing section and names no tool the session lacks. This is the assertion that would have caught the defect the story exists for: every pack-level test passed while 5,161 chars of skeleton framing rode in front of them. - NO RULE STOPPED FIRING, over the whole move rather than per card: every segment of the corpus AS IT STANDS WHEN THIS STORY OPENS is still delivered by some cell, against a frozen record of that corpus — the same instrument
tests/planningRuleRecutGate.test.tsuses for MOTIR-3891, and a second fixture rather than a refresh of the first, because the first is a record of a different move. - THE COST, BOTH WAYS. Skeleton and deepen cell sizes before and after. A phase split moves rules rather than deleting them, so a deepen cell falling while a skeleton cell rises by the same amount is the expected shape and the PR states both — a story that reports only the fall is reporting half a measurement.
Acceptance criteria
- The act test runs over every legal cell, per phase, and each assertion names the tool and the pattern it searched. A tool added to either surface later is covered without editing the test, because the patterns are derived from the two exported constants rather than listed.
- A driven
runGenerationPassis asserted on the DEEPEN session's real system message: no skeleton framing heading, no tool outsideDEEPEN_PHASE_TOOLS, and the card's own packs present. - Every segment of the pre-story corpus is shown reachable in the post-story one, or listed as deliberately retired with its reason. The frozen fixture records the corpus at this story's base commit and is never regenerated.
- Skeleton and deepen composed sizes are stated before and after, per cell, with any cell that grows named and justified.
- The story's changed surface meets the project's per-file coverage floor, measured at merge by the PR's own gate rather than enumerated here.
- No assertion depends on a stub of the module under test: the packs, the resolver, the composition and
buildGenerationSystemPromptare the real modules, and the only mocked seam is the LLM gateway.
Context refs
motir-aitests/planningRuleRecutGate.test.ts— MOTIR-3891's story gate, whose structure and frozen-fixture technique this follows.motir-aitests/plannerPromptAssemblyGate.test.ts— the harness that records every session's system message before silencing the deepen ones.motir-aisrc/llm/treeGeneration.ts—SKELETON_PHASE_TOOLS,DEEPEN_PHASE_TOOLS,runGenerationPass,buildGenerationSystemPrompt.motir-aisrc/llm/planningRulePacks.ts—legalPlanningRuleCells,composePlanningRules,composeSkeletonRules.
This story is NOT user-facing — a rule corpus has no surface a person watches — so it plans no acceptance video and no E2E, and accepts on its tests alone.