Mirror the two new gates into `SHARED_PLANNING_RULES` — the released-ref absence check and reproduce-before-you-call-it-broken, worded GENERICALLY because the shipped planner plans other people's products
Repo: motir-ai. One PR. The mirror half of MOTIR-2614, split out by guard #5 on 2026-08-10 — a rule has TWO homes and that is TWO cards, not one card with two PRs.
blocked_by MOTIR-2614: this card LIFTS that card's merged wording rather than re-deriving it, so it genuinely depends on it. Do not start before MOTIR-2614's plan-rules.md change is on origin/main.
What to mirror
Two limbs, both authored in motir-meta/prompts/plan-rules.md by MOTIR-2614:
- Gate 2, absence direction, extended to a git REF. An absence asserted of a TAG / BRANCH / RELEASE is discharged by reading THAT ref, not the default branch. A reading of the default branch is evidence about the default branch only.
- Gate 13, a limb mirroring (a). A card asserting a DEFECT IN a published artifact must OBTAIN that artifact and reproduce the defect by the same consumer-side route limb (a) already requires for calling one delivered.
⚠️ The constraint that shapes the wording — verified, not assumed
tests/treeGeneration.test.ts (origin/main, the "is a GENERIC planner" case, ~:477) asserts:
expect(r).not.toMatch(/motir-core|motir-ai|open-core/i);
expect(r).toMatch(/straddle TWO REPOS \(whatever the project's repo boundary is\)/);
SHARED_PLANNING_RULES plans ANY customer product, so the mirrored text must name no Motir repo, no GHCR, no npm package, no cli-v* tag, and no @motir/cli. Phrase both limbs in the generic vocabulary the constant already uses — "a released ref", "the project's registry", "the artifact's consumer" — exactly as the existing one-repo-one-PR rule is phrased generically. A verbatim copy of the motir-meta prose will fail that test, and this is the whole reason the mirror is its own card rather than a copy-paste.
Do this
- Read MOTIR-2614's merged
plan-rules.mdwording; restate it generically insideSHARED_PLANNING_RULES(src/llm/treeGeneration.ts, the constant at ~:829), beside the gate-2 and gate-13 material already there. - Add per-limb assertions to
tests/treeGeneration.test.tsin the shape the file already uses — onedescribe/itper mirrored rule, matching on a distinctive phrase. That per-ruleitIS this repo's rule-parity mechanism; there is no test that diffs againstmotir-meta(it cannot see that repo). - Re-run the genericity case and the full
treeGenerationsuite.
Acceptance criteria
SHARED_PLANNING_RULEScarries the released-ref absence limb: an absence claimed of a tag / branch / release is discharged by reading that ref, and a reading of the default branch is evidence about the default branch only.SHARED_PLANNING_RULEScarries the reproduce-the-defect limb: a card asserting a defect in a published artifact must obtain that artifact and reproduce the defect, by the consumer's route.- Neither addition names a Motir repo or artifact — the existing genericity case (
not.toMatch(/motir-core|motir-ai|open-core/i)) still passes, and noghcr,npm,@motir/, orcli-vstring enters the constant. tests/treeGeneration.test.tsgains oneitper limb asserting a distinctive phrase from each, following the file's existing per-rule pattern.pnpm testpasses for the changed files;tests/planningTurnGate.test.tsstill passes (it imports the same constant).- The PR title carries
MOTIR-<this card's id>(a code repo — the sync links it), and the PR body names MOTIR-2614 as the wording it lifted.
Context refs
src/llm/treeGeneration.ts—SHARED_PLANNING_RULESat ~:829; its own comment calls it "the encoding ofplan-rules.md".src/jobs/handlers/replan.ts:8— imports the constant, so a rule missing here is missing from re-planning too, not just fresh generation.tests/treeGeneration.test.ts— the genericity case at ~:477 and the per-ruledescribeblocks to copy.tests/planningTurnGate.test.ts— the second importer.- MOTIR-2614 — the
motir-metawording this lifts.
Out of scope
plan-rules.md and notes.html — both are MOTIR-2614's repo.