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-3429

Planning bug: MOTIR-3414 cannot close — its `manual` post-deploy child needs the merge the story needs the child for, and the E2E is edged to it while forbidding the worker it needs

Done
Description

Found by motir run MOTIR-3414, 2026-08-23, after landing seven of the story's nine children. The run stopped at the two that remain. Correction submitted as plan cmt6hq4xd005yi3n8vao5519i.

The defect: the story cannot complete in the shape it was planned

Two children make MOTIR-3414 un-closeable, and the first of them is a circular dependency with the story's own pull request.

A — MOTIR-3425 is a post-deploy child inside the container it must outlive

MOTIR-3425 (type: manual) is an operator card whose own step 1 reads:

Deploy the branch carrying the [processes] worker entry (this happens via CI on merge).

So it cannot begin until MOTIR-3414's pull request has merged. But a parent-run opens the parent→main pull request only once every child has landed. No PR until 3425 is done; no 3425 until there is a merge. The story deadlocks on itself, and no run of it can ever finish.

And the obvious escape is the worse outcome. Opening the PR anyway completes the container, which CASCADES done onto every child from any status — so 3425 would close green, unverified, with no machine ever scaled and no platform read ever taken. That is precisely the MOTIR-3010 shape, whose own planning bug is MOTIR-3153, recurring in a story planned five days later.

B — MOTIR-3427 is edged to a card it does not consume, and contradicts itself besides

Two separate faults on one card:

  1. The blocked_by on MOTIR-3425 is wrong on the card's own terms. MOTIR-3427 is a Playwright E2E: it runs against a local server and a local Postgres, and nothing in it reads a Fly machine or the Machines API. It consumes nothing MOTIR-3425 produces. The edge exists only to drag the E2E behind the deadlock in (A).

  2. Its criteria cannot both hold. It requires the pilot job to run "against the Postgres engine, driven through the real UI" AND that "it runs in the standard Playwright lane with no bespoke server configuration". Read on this branch:

    playwright.config.ts → webServer: [
      { command: 'prisma generate && next build && next start …' },   // the app
      { command: '<inngest-cli> dev …' },                             // the OLD engine
    ]
    

    Two processes, neither a Postgres-engine worker. The engine is a separate process group by design — that separation is MOTIR-3421's whole point — so a run queued onto it has nothing to claim it in this lane, and the spec would hang at its own step 3. The lane needs a third webServer entry, exactly as the old engine has one.

Why this is a PLANNING bug and not a card defect

No deliverable is wrong and nothing needs rebuilding. Seven children are committed and green. What failed is the SHAPE: a container was planned with a child that can only run after the container ships, and a sibling was edged to it for no consumption relationship. Both are decisions about where cards SIT and what they DEPEND ON — settled at skeleton time, unfixable by a deepen, and invisible to every readiness signal (ready, openBlockers, validate_work_item all agree the story is fine).

The mechanism, and it is worth recording because it is general

A type: manual operator card that verifies a DEPLOYMENT is not a child of the story that deploys it. It is a sibling the story blocks. The plan-time tell is textual and greppable: the card's own steps say "on merge", "after the deploy", "read it back from the platform". Any of those inside a container means the container cannot complete around it.

MOTIR-3153 recorded this once already. Its recurrence here suggests the rule needs a mechanised check rather than more prose — validate_work_item already returns shape advisories (likely-ordering-violation fires on a criterion reading post-merge state), and the same detector run against a card's STEPS, scoped to type: manual children of a container, would have caught this at plan time. Worth deciding whether to widen it rather than restating the rule.

Acceptance criteria

  • MOTIR-3425 sits OUTSIDE MOTIR-3414 — re-parented to the epic, with MOTIR-3414 blocks it. (⚠️ A re-parent cannot be expressed in a plan patch: modify.patch carries body, sizing, repo and edges, not parentRef. It is move_to_parent, run by whoever approves the plan.)
  • MOTIR-3427 no longer carries a blocked_by on MOTIR-3425, and its body states the third webServer entry as its work rather than forbidding it.
  • A decision is recorded on whether the likely-ordering-violation detector should widen to a container's manual children, or whether the prose rule is judged sufficient and this was a miss.

Evidence provenance

Every claim above was read on parent/MOTIR-3414-postgres-job-engine, branched from origin/main@165f1485: the webServer array from playwright.config.ts, the step text from the cards themselves, and the cascade behaviour from the parent-run rule that governs this run. No figure here was taken from a card's own description without checking it.

Advisory disposition (validate_work_item, at filing)

Four reference advisories fired — MOTIR-3414, MOTIR-3421, MOTIR-3425 and MOTIR-3427, three of them likely-missing-edge.

All four are DELIBERATE EXCLUSIONS, stated here because an absent edge and a considered exclusion are the same absent edge and only saying so tells them apart.

This card consumes no OUTPUT from any of them. It names them because they are its SUBJECT: the fix is a restructure applied TO those cards, and the substrate it reads — playwright.config.ts's webServer array and the cards' own step text — is on origin/main and on this run's branch already. Nothing it needs is waiting to be built.

Wiring blocked_by would invert the dependency that actually holds: MOTIR-3414 cannot complete UNTIL this correction is applied, so blocking the correction on the story would deadlock the pair in the same way the story is already deadlocked on MOTIR-3425. The edges that matter are the relates_to links, which record what this is about without claiming it waits on them.