Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-3334Done

childStatusCascadeService exempts `bug` children — delete the carve-out; MOTIR-3229's incident was a parent declared done over unfinished children, not a kind problem

Repo · motir-core. childStatusCascadeService exempts every bug child from the downward cascade. It should not. A bug that is a CHILD of a parent run is fixed BY that run — its commit is in the very pull request whose merge woke the cascade — so leaving it open contradicts the merge that closed it.

⚠️ Two things this card does NOT propose (Yue, 2026-08-21)

  • The event-driven cascade is RIGHT and stays. An earlier draft proposed settling the whole subtree in one transaction; that is withdrawn. A merge is one fact, the subtree it settles can be large, and a background reconciliation is the honest shape. The write-per-child and the delay are not the defect.
  • The CHILD'S KIND IS NOT THE DISCRIMINATOR, and no replacement discriminator belongs in the cascade. The containment belongs upstream — see the root cause below. isCascadeExempt should be deleted, not made cleverer.

What the exemption costs, measured on a live merge (2026-08-21)

MOTIR-3232 — thirteen children — merged as #2237. From get_work_item_activity:

10:00:40   PR #2237 merged
10:00:42   MOTIR-3232   In Review → Done
10:02:34…36   eleven SUBTASK children  Implemented → Done
              MOTIR-3236  (bug)  — skipped by the exemption
              MOTIR-3240  (bug)  — skipped by the exemption
10:03:30   MOTIR-3232   Done → IMPLEMENTED     ← the rollup counts what the cascade may not complete

Both skipped cards were planned children, claimed and built by the run: MOTIR-3236's fix is commit 6d1c3340, MOTIR-3240's is c3e2b5c4, both inside #2237. They were left open because of their kind, against the evidence of their own merged code.

And the story did not merely lag — it was pulled back out of done, because parentStatusRollupService states in its header "No work item is exempt: there is no per-item or per-kind carve-out." The upward half counts children the downward half is forbidden to complete, so the end state is stable and self-perpetuating. It sat at implemented until both bugs were closed by hand, after which the rollup pulled it up on its own. Deleting the exemption fixes both halves at once: there is then nothing left for the two services to disagree about.

⚠️ MOTIR-3229's incident was diagnosed at the WRONG LAYER — and the kinds were never the issue

The exemption exists because of a real loss: MOTIR-1343's run filed two defect reports under the story while shipping it, and both were closed out from under a session three minutes into investigating them. MOTIR-3229 concluded that a bug must be exempt. That is a fix to the symptom. The measured history says so:

11:24:59  MOTIR-1343  In Progress → Implemented
11:31:18  MOTIR-1343  Implemented → In Review      ← the parent run opened its pull request
13:27:15  MOTIR-1343  In Review  → Done            ← merged
13:41:45  MOTIR-3218  To Do → In Progress          ← FILED AND CLAIMED 14 MINUTES LATER,
13:41:56  MOTIR-3219  To Do → In Progress             under a parent that was ALREADY done
13:44:35  MOTIR-3218  In Progress → Done           ⎫ swept, 36ms apart
13:44:35  MOTIR-3219  In Progress → Done           ⎭
14:06:57  MOTIR-3219  Done → In Progress           ⎫ the recovery, by hand
14:07:10  MOTIR-1343  Done → In Progress           ⎭
14:57:19  MOTIR-1343  In Review → Done             ← redone properly

The children were in_progress when they were swept, and kind is not what made them vulnerable. filterNotDone keeps every child not in a done-category status and the cascade completes them all — so an in_progress subtask in the same position would have been swept identically, with no exemption to save it. The exemption protects one kind-shaped slice of a kind-agnostic hole.

The hole is that a parent's done-ness was declared over children that were not finished. Two forms of it, and this card asserts only what the history above shows:

  1. A parent run must not open its pull request and move the parent to in_review while any child is unimplemented — regardless of kind. (Yue's statement of the rule. MOTIR-1343 satisfied it at 11:31, when neither child existed yet, so this timeline is not its instance — but the rule is the containment for the general case and belongs with this card's decision.)
  2. A child must not be filed under a parent that is already finished — which IS what this timeline shows, and is where MOTIR-1343 actually lost its findings.

⚠️ What is NOT established: why the cascade fired at 13:44:35 when the parent's own in_review → done was at 13:27:15 and no parent transition is recorded at 13:44. Whoever takes this should pull that Inngest event rather than infer it — three mechanisms have already been asserted from partial evidence in this lineage and corrected.

Acceptance criteria

  • isCascadeExempt and its kind carve-out are DELETED. A bug child that the run built is completed by the parent's merge; a test covers the MOTIR-3232 shape and fails against today's code.
  • The parent settles at done and STAYS there. The regression test asserts the state after the rollup has run, not just after the cascade — the incident above passed the cascade and failed 54 seconds later.
  • The containment is placed upstream, not in the cascade: a parent may not be moved to in_review (nor its pull request opened by a parent run) while a child is unimplemented, and the guard is kind-agnostic. If that guard already exists for implemented (lib/workItems/statusLadder.ts is shared with a gate that refuses a container's claim to be built while a child is not), this card says why it did not cover in_review.
  • A child created under an already-done parent does not inherit that parent's doneness — the MOTIR-1343 shape, tested from its own evidence.
  • childStatusCascadeService's header and isCascadeExempt's doc block are rewritten rather than deleted wholesale: they carry MOTIR-3229's measurement, which stays true, and the new text should say why the conclusion drawn from it moved layers.
  • The rollup's "No work item is exempt" claim is re-read against the result — with the exemption gone it becomes consistent, and the comment should say so instead of standing beside a sibling that contradicted it.
  • Trees already stranded are identified and repaired; the query that finds them is recorded here. (MOTIR-3232 was repaired by hand on 2026-08-21 — see the comments on MOTIR-3236 and MOTIR-3240, each closed on the evidence of its own commit.)

Context refs

  • lib/services/childStatusCascadeService.tsisCascadeExempt, filterNotDone, and the MOTIR-3229 doc block.
  • lib/services/parentStatusRollupService.ts — the recompute and the "no carve-out" claim.
  • lib/workItems/statusLadder.ts — the shared rung ordering, and the gate that already refuses a container's claim to be BUILT while a child is not.
  • lib/services/changeRequestStatusSync.ts — the merge-driven flip.
  • docs/decisions/run-findings-protocol.md Q3 — why a found bug is parented where it was FOUND, which is what puts an unfinished child under a shipping parent in the first place.
  • The incidents: MOTIR-3232 / PR #2237 (the exemption's cost), and MOTIR-3229 / MOTIR-1343 / MOTIR-3218 / MOTIR-3219 (the misdiagnosed one).