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
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:
-
The
blocked_byon 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). -
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
webServerentry, 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
blocksit. (⚠️ A re-parent cannot be expressed in a plan patch:modify.patchcarries body, sizing, repo and edges, notparentRef. It ismove_to_parent, run by whoever approves the plan.) - MOTIR-3427 no longer carries a
blocked_byon MOTIR-3425, and its body states the thirdwebServerentry as its work rather than forbidding it. - A decision is recorded on whether the
likely-ordering-violationdetector should widen to a container'smanualchildren, 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.