Repos · motir-meta + motir-ai, in that order. A rule change, not product code — and a standing planning RULE has TWO homes, so this card carries both: the runbook the manual planner reads (prompts/) and SHARED_PLANNING_RULES, which the shipped planner reads. It completes only when BOTH have merged.
⚠️ RE-FILED 2026-08-25 23:0x — the original premise was rejected (Yue)
This card was first filed as a
motir-coredefect inparentStatusRollupService: "a card that carries its own acceptance criteria is completed by its PREREQUISITE child's merge." That is not a bug. The rollup's rule — every childdone⇒ the parent isdone— is correct, because a child IS a parent's content. What was wrong is the SHAPE it was fed: the design card was made a child of the card it gated. A design prerequisite is a SIBLING wiredblocked_by, never a child. The producer of the wrong shape isrun.mdguard #3, and that is what this card changes. Nothing inmotir-coreis touched.
During motir run MOTIR-3490 on 2026-08-25:
design/roadmap/ depicted neither the grouped root node nor a truncated level. Correct so far.type: design Subtask for the surface" — and MOTIR-3493 was created under MOTIR-3490, plus the blocked_by edge.done, and MOTIR-3490 → done in the same beat with all six of its acceptance criteria unbuilt — because from the rollup's side it had one child and that child was complete. (An earlier in_progress → in_review at ~22:07 is the same thing one rung down.)The tree has since been corrected by hand: MOTIR-3493 is now a root-level task (type: design) that blocks MOTIR-3490, with the blocked_by edge unchanged and MOTIR-3490 holding no children at all. That instance needs nothing further; this card is about the rule that produced it.
prompts/run.md guard #3 said:
If NONE exists → PAUSE. Do NOT improvise and do NOT build the UI. PROPOSE a
type: designSubtask for the surface (create_plan→add_plan_items{ op: 'add' }…), and carry the edge on the SAME plan as{ op: 'modify', workItemId: <the UI code Subtask>, patch: { blockedByAdd: [...] } }
The word Subtask is the defect. A subtask cannot be a root (prisma/sql/work_item_triggers.sql — it is the one kind that must have a parent), and ALLOWED_CHILD_TYPES admits bug → [subtask], so when the gated card is a parentless leaf the only kind-legal placement the remedy leaves is under the gated card itself. The rule never says "make it a child"; it makes a child unavoidable. And the guard's own framing — "the UI code Subtask" — assumes the gated card is a subtask hanging under a story, which is the one case where a sibling placement happens to be legal by accident.
The correct rule has nothing to do with kind: a prerequisite goes beside the card it gates, at the same level, and the ONLY thing joining them is the blocked_by edge. Its kind then follows from where it sits — subtask when the gated card has a container parent (a sibling under that same parent), task at the root or under an epic when it does not.
prompts/run.md guard #3's remedy states the placement explicitly: the proposed design card is a SIBLING of the gated card — the same parentKey the gated card has — and is NEVER parented under it, with the kind following the placement (subtask under a container parent; a root-level task when the gated card is itself parentless). The blocked_by edge stays exactly as it is today; it is what makes the sibling a prerequisite.parentStatusRollupService, so a prerequisite parented under the card it gates completes that card on its own merge. Cite the MOTIR-3490 / MOTIR-3493 fixture by key and date, one sentence, no recap.plan-rules/* files instructing the planner to add a type: design card for an unspecified surface, or a missing precondition, state the same rule — so a plan authored from scratch cannot produce the shape either.prompts/ instructs anyone to add a type: design card under the card it gates. Run it and paste the output in the PR body — the sweep is by FILE, not by remembering where the rule lives.motir-ai mirror ships in the same pass (Yue, 2026-08-25: "if motir-meta needs update, motir-ai needs too"): the rule lands in SHARED_PLANNING_RULES (src/llm/planningRulePacks.ts) — generic, unbranded, no source-file citations — with a tests/planningRulePacks.test.ts block pinning the limb AND its delivery into every cell its host reaches, and the conservation baseline refreshed through scripts/refresh-planning-rules-baseline.ts rather than by hand.parentStatusRollupService is NOT changed by this card — and the PR body says so, so a later reader does not re-open the rejected premise.run.md (the named rule + guards #3/#4), plan-rules/core.md gate 4, plan-rules/kind-leaf.md, plan-rules/kind-bug.md, _shared.md, plan-procedure.md. Guard #5 audited and already correct (it proposes a sibling per repo).THE_DESIGN_GATE + VERIFY_EVERY_PRECONDITION, the test block, the refreshed baseline.subtask/MOTIR-3496-prerequisite-is-a-sibling; both PR titles carry the key, so the first merge defers and the last one closes the card.prompts/run.md — guard #3 (the design gate, the producer), guards #4/#5 (the same shape), and the motir run CREATES NO WORK ITEM EXCEPT A bug block that already carries the edge-on-the-same-plan mechanics.prompts/plan-rules/core.md gate 4 · prompts/plan-rules/kind-leaf.md (the planning-time design gate) · prompts/plan-rules/kind-bug.md — the plan-time half.motir-ai/src/llm/planningRulePacks.ts — SHARED_PLANNING_RULES; tests/planningRuleConservation.test.ts is the guard that goes red on a re-word.motir-core/lib/issues/parentRules.ts — ALLOWED_CHILD_TYPES / TYPES_REQUIRING_PARENT: why "Subtask" forces the child placement; read, not changed.motir-core/lib/services/parentStatusRollupService.ts — agg.done === agg.total, the rung ladder, and the agg.total === 0 guard that makes an EMPTY parent safe; read, not changed.