PLANNING RULE (motir-meta) — a design that allocates ONE surface across N consuming cards emits N−1 edges BETWEEN them; the design's own `blocks` fan-out is not those edges
Repo: motir-meta. One PR — ALREADY OPEN as PR #100 (docs/design-allocation-emits-consumer-edges). This card RECORDS work that was authored during motir run MOTIR-2080 as guard #4's mandated corpus record; it is filed after the fact so the shipped-planner mirror (MOTIR-2099) can hang off a blocked_by EDGE instead of a prose precondition — which is, precisely, the rule this card adds.
The incident it was drawn from
MOTIR-2087 amended design/coding-convention/ with Panel 4b: /code-health's single !audit empty state becomes four states, allocated across two consuming cards by a "Built by" table — State A's branch and State B's copy to MOTIR-2081, State B's action plus States C and D to MOTIR-2080.
The design was wired blocks to BOTH consumers and nothing was wired between them (they carried relates_to). The merge therefore released a fan-out — two peers, both ready — where the allocation table describes a chain. motir run MOTIR-2080 claimed the downstream card and found, against origin/main, that page.tsx:58 resolves repos and drops it, CodeHealthClient has no repo prop to forward, and AuditPanel.tsx:55 is one repo-blind early return: the card's whole deliverable renders INSIDE a state its sibling builds.
What the PR lands
prompts/plan-rules.md— the corollary, placed under the existing UI-composition rule (⚠️ The HOST SURFACE a UI card renders INSIDE is ablocked_by, not arelates_to) that it extends.notes.htmlmistake #213 (+ the Cross-cutting patterns count, 212 → 213).
Why it is a new rule and not a footnote on the existing one
The existing rule is already exact — it was logged as notes.html #143 against MOTIR-1592, on this same /code-health surface, and says a host recorded as relates_to "makes the card falsely-READY with nowhere to render." Two things defeat it here:
- Where the evidence lives. #143 looks for a host noun in the consuming card's OWN description and expects a whole surface with its own build card. Here the host is a state of a screen that already ships, the card never names it as a host, and the dependency is written down only in the DESIGN's notes. An allocation table is read as scope, never as topology — yet it is both.
- The automation could not compensate.
validate_work_itemreturnedvalid: true, no blockers, no advisories — the prose-vs-graph detector keys onMOTIR-<n>, and the criterion names its sibling as "see the sibling bug on the empty state's repo-awareness". An unlinked prose reference produces no blocker and no advisory.
Acceptance criteria
prompts/plan-rules.mdcarries the corollary adjacent to the UI-composition rule it extends, not as a free-standing section.notes.htmlcarries mistake #213 with the standard.mistakemarkup (What happened · Why the existing guards missed it · Lesson · Prompt hint), and the Cross-cutting patterns count is bumped.- The lesson cites #143 as the parent shape and states what is NEW rather than restating it.
- Branch is
docs/<slug>with noMOTIR-<n>in the branch OR the PR title (motir-meta is a linked repo — an id there would bind the status sync to a card whose deliverable ships elsewhere).
Close-out
No status sync will fire — this repo's PRs deliberately carry no MOTIR-<n>. On merge, transition this card by hand (in_progress → in_review → done) after verifying the two files on origin/main.
Context refs
- PR #100 — the open PR that IS this card's deliverable.
prompts/plan-rules.md— the UI-composition / host-surface rule the corollary extends.notes.html#143 (the parent shape, MOTIR-1592) and #210 (the prose-vs-graph advisory that could not fire).- MOTIR-2099 — the motir-ai half; a RULE has two homes.
- Precedent for the two-card split: MOTIR-2083 → MOTIR-2089.