Planning bug: a card whose precondition is a DEPLOY was gated by a `blocked_by` edge, which discharges at MERGE — the RULE half (the lesson shipped)
Filed by motir run MOTIR-3803, guard #4. The correction to the tree is already submitted as plan cmtdbfgzs01f4hwn8q085dp9u, and the LESSON half is already shipped (below); this card is the telemetry plus the one piece of the fix that remains. It holds nothing up.
⚠️ SCOPE NARROWED BY THE FILING RUN, 2026-08-28. As authored this card owed two things — a lesson row in
motir-aiand a rule inmotir-meta. The lesson is amotir run's own mandatory obligation and may not be deferred to a card, so this run wrote it: moooon-B-V/motir-ai#323, one global row plus its generated migration, seed suite green. The card was re-pinned from["motir-ai", "motir-meta"]to["motir-meta"]and its first criterion re-stated as an already-discharged fact, so that nothing here reads as unfinished work that is in fact done. What remains is the RULE.
The defect in the plan
MOTIR-3803 is the CONTRACT half of an EXPAND/CONTRACT pair: it drops github_check_run.feedback_comment_id once the per-card table added by MOTIR-3770 is live. Its explanation states the precondition three separate times and unambiguously — "once the new build is everywhere", "a planned second step whose precondition is a deploy", "an instance still serving the previous release … gets a column-not-found on every CI delivery".
The only gate it was given is blocked_by MOTIR-3770. A dependency edge is discharged when the blocking WORK completes, and for a code card that is the MERGE. So:
2026-08-28T18:53:36Z MOTIR-3770 merges (62dd1366f) → status done → edge discharged
2026-08-28T18:53:36Z MOTIR-3803 readiness.ready flips true, openBlockers: []
2026-08-28T18:55:08Z motir run MOTIR-3803 claims it — 92 seconds later
At claim time, measured rather than assumed:
flyctl releases -a motir-core→ current release v183, created2026-08-28T11:35:16Z, 7h18m before the merge; all four machines on that deployment tag.- MOTIR-3770's
mainCI run: stillpending. Thedeployjobneeds: [lint, typecheck, build, test, coverage, e2e, e2e-at-scale], so no release had even been attempted. - Production DB, read inside machine
7817663f103648overDATABASE_URL_UNPOOLED:select to_regclass('public.github_ci_feedback_comment')::text→null.
Had the run trusted ready: true, it would have dropped a column that every running production instance still selects.
Why this is a class, not one card
A blocked_by edge cannot express a deploy. The graph has exactly one notion of "finished", and for code it is a merged pull request. Nothing about the tree changes when a release rolls, so no arrangement of edges between work items can gate on one. Every EXPAND/CONTRACT pair, every "flip the flag once the new path is proven", every "backfill has run in production" card has this shape, and each of them currently fails the same way — silently, and in the reassuring direction: the card reads ready: true, openBlockers: [], valid: true, and the only thing that says otherwise is a paragraph no mechanism reads.
And the better the paragraph, the more certainly it is dropped. MOTIR-3803's explanation is unusually good — it names its reason, identifies the consuming half precisely, and states its own release condition — which is exactly what makes it read as scheduled. Nothing walks back from the deploy finished to a sentence that was waiting on it. The card is itself the fix for that same failure one level down (it exists because MOTIR-3770's deferral was a paragraph), and it reproduced the mistake in its own gate.
What the fix changes
A lesson row in— DONE, moooon-B-V/motir-ai#323. Global scope by the strip-the-identifiers test: a precondition that is a RELEASE cannot be carried by a dependency edge; the edge is discharged by a MERGE. One curated row inmotir-aisrc/seed/lessons.base.ts+ its generated forward-only migration. Deliberately paired in its own comment with the existing container-placement row (sourceRef: MOTIR-3794) so neither is read as covering the other: that one is about where a post-deploy card should HANG, this one about what an EDGE can mean between two ordinary siblings.- A planning rule in
motir-metaprompts/plan-rules/— THIS CARD'S REMAINING SCOPE. The natural home is the precondition-verification limb inphase-deepen.md, with a pointer fromcore.mdgate 4: when a card's prose says deployed / released / rolled out / live / in production / once N is running / after the migration has run, the edge it needs is to atype: verificationcard whose criteria read the PLATFORM — not to the card that ships the change.run.mdguard #4 is the run-time backstop that caught this one, and it should say so, so the two tiers cite each other rather than drift.
Acceptance criteria
- Already discharged — verify, do not rebuild.
motir-aicarries the global row and its generated migration (#323). Confirm it merged and thattitle/body/howToApplystill name no repository, key or path; if #323 was closed unmerged, re-open that work under a card of its own rather than folding it back in here. motir-metacarries the rule in the pack that owns preconditions, phrased as a check an author runs at plan time, with the trigger words enumerated so it is grep-able.run.md's guard #4 names this class explicitly as the case it backstops, and cites the pack rule; the pack rule cites guard #4. A rule with two homes is stated once and pointed at from the other (planning-rule-has-two-homes).- The rule and the lesson are checked against each other for contradiction — the lesson's
howToApplyis the runner's version, the pack rule is the author's, and they must prescribe the same instrument (averificationcard reading the platform). - ORDERING — nothing here reads MOTIR-3803's branch or the
motir-coredeploy. This card is dischargeable frommotir-metaalone, at any time, before or after that release lands.
Context refs
- MOTIR-3803 — the card that halted; its comment carries the full measurement.
- Plan
cmtdbfgzs01f4hwn8q085dp9u— the submitted correction (theverificationgate card + theblockedByAdd). - moooon-B-V/motir-ai#323 — the lesson row, already shipped.
motir-meta/prompts/run.md— guard #4, and A RECORDED DEVIATION that names an OPEN defect is abugto FILE, whose reasoning this card extends from a defect-in-prose to a precondition-in-prose.- Global lesson
cmr11gsxh0003kdqzv7e5mc1l"Every prose precondition must be a real dependency edge" — reinforced against this occurrence (recurrenceCount→ 3). It is the nearest existing row and it is insufficient here: its remedy is wire the edge, and the edge WAS wired. That gap is what #323 adds and what item 2 teaches at plan time.
Comments (0)
No comments yet — be the first to weigh in.