A RECORD card. The plan correction is already applied — plan cmt5jdmsy00f1i3phkn9ycs7k, submitted 2026-08-23 by motir run [MOTIR-3313](motir:cmt2an72n000di4phf6t97lts) and awaiting approval.
motir run MOTIR-3313 claimed a childless bug and halted at guards #2 and #4 before creating a worktree. The card carried:
## Acceptance criteria section at all — its remaining work was two sentences under What this card is still for, beginning "Find out…" and "Consider whether…";type: null, executor: null, storyPoints: null, estimateMinutes: null, targetRepo: null, explanationMd: null;Every automatic signal agreed it was startable: readiness.ready: true, openBlockers: [], validate_work_item → valid: true, advisories: [].
(1) The corpus has no rule about a card carrying NO acceptance criteria. Every plan-time gate that would have caught this card is stated over criteria — gate 14's three axes read each criterion, gate 17 asks whether each criterion is owed under every hypothesis, kind-leaf-deepen.md's precondition-wearing-a-checkbox rule judges a criterion by what its sentence describes. A card with zero criteria satisfies all of them vacuously. Measured 2026-08-23, all three homes at 0:
grep -rain "no acceptance criteria|without acceptance criteria|zero criteria|carries no criteri" \
prompts/plan-rules/ prompts/run.md prompts/plan-procedure.md → 0
git grep -ain (same pattern) -- motir-ai/src/llm/ → 0
Gate 16 names the STRUCTURE (descriptionMd = body + ## Acceptance criteria + ## Context refs) but states no check on its absence, and phase-deepen.md's "a card with explanationMd: null is UNDER-AUTHORED, exactly like one with no ## Acceptance criteria" is an analogy, not a gate — it names the condition while checking a different field.
(2) The mechanised half of the estimation gate is blind to an UNSIZED card, by two independent guards. overGateSizing (lib/workItems/proseVsGraph.ts, read on origin/main) opens:
if (card.executor !== 'coding_agent') return null;
…
const overPoints = storyPoints !== null && storyPoints >= ESTIMATION_GATE_STORY_POINTS;
const overMinutes = estimateMinutes !== null && estimateMinutes > ESTIMATION_GATE_ESTIMATE_MINUTES;
MOTIR-3313's executor is null, so the check returns at line 1 — the detector requires exactly the field an under-authored card is missing. And even with an executor set, both arms are !== null-guarded, so a null-sized card is invisible. The gate's prose says plainly "any LEAF with a null story_points or null estimate is a planning bug" — the mechanised form only ever looks for over-sized, never un-sized, which is the commoner and quieter failure.
So the prose gate that covers (2) exists and was not performed, and the detector that would have performed it cannot see the case. That is why nothing anywhere went amber.
An ## Acceptance criteria heading with at least one criterion, and a non-null storyPoints / estimateMinutes, as a condition of sealing a leaf — checked rather than assumed. Both are string-and-integer level checks over fields the card already carries, with no reference resolution and no DB read — the same cheapness sizingAdvisory's own comment claims for itself ("two integers and an enum"). By CORPUS-MAINTENANCE.md's THIRD TIER that puts them in code, not in prose.
⚠️ Decide the rule-vs-lesson question at close-out, not here, and read MOTIR-1464's not-done children FIRST — a W card for this family may already exist, and a duplicate splits the warrant of the rule it is trying to strengthen. Note when you do: this is not a "widen an enumeration" case — the trigger words are absent from all three homes, which is a totality gap.
Submitted as plan cmt5jdmsy00f1i3phkn9ycs7k (2 adds + 1 modify), not written into the tree — a run proposes:
targetRepo: motir-core and its missing explanationMd.manual / human child for the Tigris support request — the only route to the two request ids, written so a documented refusal closes it.decision / coding_agent child for the recoverability question, deliberately not blocked_by the first, because it is owed under every hypothesis the parent card left open.likely-missing-edge → MOTIR-3313, DELIBERATELY NOT WIREDvalidate_work_item on this card (2026-08-23) returns one advisory: this card's criteria name MOTIR-3313, which is blocked, with no blocked_by edge. The edge is refused, and the reason is written here because an absent edge and a considered exclusion are the same absent edge.
This card is closed against the plan being DECIDED — an act available to a person today — and not against MOTIR-3313 reaching done. Those are different events with different clocks. MOTIR-3313 now contains a manual child waiting on a vendor's support mailbox, so a blocked_by edge would hold a twenty-minute record open for however long Tigris takes to answer, or for ever if they never do. That is precisely the defect this card records, reproduced on the card that records it — and it is the shape Yue flagged on MOTIR-1748: a record card's subject is a graph you verify by READING, so its own future does not gate the reading.
The criterion below is therefore worded to read on the PLAN's decision. relates_to carries the discovery trace, which is the correct relation for a card that reports on another rather than consuming it.
cmt5jdmsy00f1i3phkn9ycs7k has been decided — approved, or declined with a reason — and this card records which, and (if approved) that the materialized shape matches what the plan proposed: the two children present with their types, executors and sizes, and the survivor carrying targetRepo: motir-core and a non-null explanationMd. A decline is a valid close too, recorded with Yue's reason.motir-ai src/seed/lessons.base.ts on origin/main, located by content, not by a citation.MOTIR-1464's not-done children are read before any rule card is filed, and this card records whether an existing W card ABSORBS this finding (amend it) or a new one is owed (file it) — with the reason either way.overGateSizing returns at its executor guard, and both arms are !== null-guarded). A disposition that addresses only one of them says why the other needs none.relates_to, not blocked_by — see the disposition above.prompts/plan-rules/core.md — the per-card gate checklist; gates 14, 16 and 17 are the ones that read criteria.prompts/plan-rules/kind-leaf-deepen.md — THE ESTIMATION GATE, and "any LEAF with a null story_points or null estimate is a planning bug".prompts/plan-rules/phase-deepen.md — the both-content-axes rule, whose "exactly like one with no ## Acceptance criteria" is the analogy that names this condition without checking it.motir-core lib/workItems/proseVsGraph.ts — overGateSizing, its executor guard and its two !== null arms.motir-core lib/services/proseGraphAdvisoryService.ts — sizingAdvisory, and the advisory families validate_work_item returns.prompts/plan-rules/CORPUS-MAINTENANCE.md — THE THIRD TIER, the rule for when a check belongs in code rather than prose.