Mirror the request-COUNT precondition limb into `SHARED_PLANNING_RULES` — the shipped planner must refuse an uncited request budget too
Repo: motir-ai. One PR. The second home of the rule MOTIR-2446 lands in motir-meta/prompts/plan-rules.md.
Why this card exists
A standing planning RULE has TWO homes, and 2446 named only one:
motir-meta/prompts/plan-rules.md— the MANUAL planner.SHARED_PLANNING_RULESinmotir-ai/src/llm/treeGeneration.ts— the SHIPPED planner. Its own comment calls it "the encoding ofplan-rules.md", and it is composed by both fresh tree generation and re-planning (src/jobs/handlers/replan.tsimports it), so a rule missing here is missing from every plan the product generates.
Landing the rule in motir-meta alone teaches the manual planner while the product keeps planning the old way — the opposite of dogfooding. This is the same miss recorded twice before (MOTIR-1773 → MOTIR-1774; MOTIR-2083 → MOTIR-2089) and now a third time, which is itself noted in notes.html #243.
What to mirror
LIFT the wording from plan-rules.md's request-COUNT limb (added by MOTIR-2446, sited in the precondition-verification gate beside the data-seam rule) — do not re-derive it. Compressed to the constant's register, it must preserve all four load-bearing parts:
- A criterion constraining how many requests something costs ("once per run" · "one request" · "not per item" · "no additional request") is a claim that some operation answers for a SET — name it as
GET <path>→<Component>[], or drop the number. - The discharge is an ENUMERATION, not a recall: (a) which components carry the field, (b) map EVERY path to the component in its
200response and read off which are collections. (b) is the step that gets skipped. - Write both lists in one vocabulary (component names) — a term cannot be reconciled against a prose description.
- It applies to the ABSENCE direction too, which is the dangerous one.
Scope BOUNDARY
SHARED_PLANNING_RULES (and its test) only. It does NOT change any job handler, prompt assembly, or generation behaviour beyond the rule text. It does NOT touch motir-meta — that is MOTIR-2446's PR, which this card is blocked_by.
Acceptance criteria
SHARED_PLANNING_RULESinsrc/llm/treeGeneration.tscarries the rule with all four parts above, in the constant's existing register and formatting.- The wording is lifted from the merged
plan-rules.mdlimb rather than re-derived — quote the source paragraph in the PR body beside the mirrored text so the two are diffable by eye. - A test asserts the constant contains the rule (match the existing assertions' style in the constant's own spec — enumerate them first rather than assuming the file name).
- Both the fresh-generation and re-plan composition paths still include the constant — asserted, not assumed:
src/jobs/handlers/replan.tsimports it and that import is covered.
Context refs
motir-ai/src/llm/treeGeneration.ts—SHARED_PLANNING_RULES. ⚠️grepsilently finds nothing in this file (very long lines) — search with python/node.motir-ai/src/jobs/handlers/replan.ts— the re-plan composition path that imports it.motir-meta/prompts/plan-rules.md— the source wording (MOTIR-2446).- MOTIR-1774 / MOTIR-2089 — the two prior mirrors, for precedent on shape and size.
- Story: MOTIR-1855.