MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-3341

Planning rule: NEVER reopen a `done` work item — plan forward, and log a bug or a new story instead

Done
Description

Repos · motir-meta + motir-ai (a standing planning RULE has two homes; one card, two repositories, primary first).

The rule (Yue, 2026-08-21)

Never reopen a done work item. We plan FORWARD. If a done item turns out not to be done, LOG A BUG or file a NEW STORY.

A done card is a record that something shipped. Dragging it backwards rewrites that record, and it does not even do the job: the thing that is now wrong is new information, and new information gets a new card. The corrective path already exists and is already sanctioned — motir log bug writes directly, is purely additive, and claims no scope — so this rule adds a PROHIBITION to a corrective route that is already built, rather than asking for a new mechanism.

⚠️ This EXTENDS an existing rule; it does not open a new axis

The corpus already says "we only plan FORWARD" — and it is scoped to PARENTING: never give a not-done card a done parent, because a create recomputes the parent from its current child set, applies the result BACKWARD, and the re-open climbs the whole ancestor chain, dropping every later blocked_by dependent out of the ready set.

  • prompts/plan-rules/kind-bug.md — the home of the rule (the "we-only-plan-forward" limb, the three-step parent choice, the discovery-trace-by-edge rule).
  • prompts/plan-rules/core.md (~line 415) and prompts/plan-rules/op-replan.md (~line 215) — cross-references that restate it and point back to kind-bug.md.
  • motir-ai/src/llm/planningRulePacks.tsSHARED_PLANNING_RULES — the shipped mirror, carrying the same limbs in the same order.

What is MISSING in both homes is the transition itself. Every existing sentence is about where a new card is PARENTED; none forbids moving a done card backwards directly. That gap is what this card closes, and naming it as an extension is what keeps the two homes' wording liftable rather than re-derived.

⚠️ The sentence that has to change, in BOTH homes

Both kind-bug.md and SHARED_PLANNING_RULES justify keeping a blocked_by edge INTO a done prerequisite like this:

"This does NOT repeal the keep-the-edge rule — a genuine blocked_by INTO a done prerequisite stays, because it re-gates correctly if a HUMAN re-opens that card. An inherited edge is latent insurance a person fires."

That justification assumes the very move this rule forbids. Under the new rule a human does not re-open the card, so the insurance is never fired that way. The keep-the-edge rule is still right — an edge into shipped work records a real dependency — but its REASON has to be restated, and the card must say what now discharges it (the new bug or story that supersedes the done card, wired in its place). Leaving the old sentence standing would put two rules in one pack that cannot both be followed.

Evidence — the move happens, and it happened in the incident this came from

MOTIR-1343's recovery, read from get_work_item_activity:

13:44:35  MOTIR-3218  In Progress → Done      ⎫ two defect reports swept by a cascade
13:44:35  MOTIR-3219  In Progress → Done      ⎭
14:06:57  MOTIR-3219  Done → In Progress      ⎫ THE FORBIDDEN MOVE — the repair
14:07:10  MOTIR-1343  Done → In Progress      ⎭ re-opened a done child AND its done story
14:57:19  MOTIR-1343  In Review → Done

The repair was made by re-opening a done story and a done bug rather than by filing forward. It worked, and it is exactly the shape this rule rules out: under it, MOTIR-3219's remaining work is a NEW bug, and MOTIR-1343 stays done because it shipped.

⚠️ In scope: DELIBERATE reopening. NOT in scope: the automatic backward derivation

parentStatusRollupService is "A RECOMPUTE, NOT A RATCHET" (MOTIR-2885): it applies its result backward as well as forward, so a done parent given a fresh todo child returns to todo on its own. That is a PRODUCT behaviour, it is what the existing parenting rule exists to route around, and it is not what this card forbids — a rule for planners cannot bind a job.

The two must not be conflated, and the interaction is worth one sentence in the rule: the automatic re-open is the reason the parenting rule exists; this rule closes the other door, the one a person walks through deliberately. Whether the automatic direction should survive at all is MOTIR-3334's territory, not this card's.

Acceptance criteria

  • prompts/plan-rules/kind-bug.md carries the rule, written as a limb of the existing we-only-plan-forward rule rather than as a new section — never reopen a done card; the corrective is a new bug or a new story; relates_to carries the trace to the card that shipped.
  • SHARED_PLANNING_RULES carries the same limb, lifted from the motir-meta wording rather than re-derived, so the shipped planner and the manual one say the same thing.
  • The keep-the-edge justification is restated in BOTH homes — the "if a HUMAN re-opens that card" clause cannot stand beside this rule. Say what discharges the edge now.
  • The rule NAMES its non-scope: the automatic backward derivation is untouched, and the card says why a planner rule cannot bind it.
  • core.md and op-replan.md's cross-references still resolve — they point at kind-bug.md's rule by name, so a renamed limb must be swept there too.
  • verify.py is NOT required to go green — it is already red on main by design (plan-rules/COMPRESSION.md § Consequences, and plan-rules.md's own header say so). Do not let a pre-existing red be read as this card's regression, and do not "fix" it here.
  • Both pull requests carry MOTIR-<n> in the title, and both are OPEN before either is merged — the completion gate counts open linked PR rows with no repo filter, so a sibling that does not exist yet counts zero and the first merge would close the card early.

Context refs

  • prompts/plan-rules/kind-bug.md — the we-only-plan-forward rule and the keep-the-edge parenthetical.
  • prompts/plan-rules/core.md · prompts/plan-rules/op-replan.md — the cross-references.
  • prompts/log-bug.md — the corrective route this rule points at, already sanctioned to write directly (MOTIR-3047).
  • motir-ai/src/llm/planningRulePacks.tsSHARED_PLANNING_RULES, the shipped mirror.
  • motir-core/lib/services/parentStatusRollupService.ts — the recompute-not-ratchet behaviour that is explicitly OUT of scope here.
  • The incident: MOTIR-1343 / MOTIR-3218 / MOTIR-3219, and MOTIR-3334 for the cascade half.