A card's acceptance criteria named a piece of shipped infrastructure as EXISTING. It did not exist, and the card's whole mechanism depended on it.
MOTIR-2082 was authored with this criterion, and this context ref:
Cross-workspace by nature, so it runs under
withSystemContext…
lib/workspaces/context.ts—withSystemContext, and themigrate_onboardingRLS policy's system-admin branch.
There is no such branch. migrate_onboarding was created (20260710042507_add_migrate_onboarding) as a deliberately pure workspace gate — the migration's own comment reads "pure workspace gate, no escape hatch":
CREATE POLICY "migrate_onboarding_active_workspace" ON "migrate_onboarding"
FOR ALL
USING ("workspace_id" = current_setting('app.workspace_id', true))
WITH CHECK ("workspace_id" = current_setting('app.workspace_id', true));
withSystemContext binds app.system_admin and not app.workspace_id, so under it that predicate evaluates workspace_id = NULL → NULL → every row hidden. A sweep built exactly to the card would have scanned zero rows and repaired nothing — passing CI, passing review, and silently never doing its job. It was caught only because the implementing run happened to open the migration to check the policy shape.
The failure mode is the dangerous one: the card did not merely omit a prerequisite (which surfaces as a build error), it asserted a false one in a context ref, which reads as verified and invites the implementer to skip re-checking. The blast radius is a job that looks healthy and does nothing — precisely the class MOTIR-1970 exists to detect after the fact.
This is notes.html #33 (verify-don't-cite) pointed at the planner's own output: the rule so far governs claims made while implementing, not claims baked into a card at plan time.
A card may not assert a code fact — a policy branch, a helper, a column, an exported symbol, a route — as existing unless it was grepped on origin/main at authoring time. If it was not, the criterion is phrased as an obligation ("add the system-admin branch if absent"), not an assumption. The tell: a context-ref line that explains what a file contains rather than pointing at where to look — the first is a claim, the second is a pointer, and only the first can be wrong.
Cheap to comply with: one git grep per asserted fact, the same check the implementing run ran in seconds.
Note this is a distinct gate from MOTIR-2083's Rule 1 (an AC must be satisfiable inside the card's own scope boundary) — that one is about REACHABILITY of an outcome; this one is about the TRUTH of a stated premise. Both fired on the same card, which is itself worth noting when landing this.
Per MOTIR-2083's two-homes rule, a standing planning RULE goes in both motir-meta/prompts/plan-rules.md (the manual planner) and SHARED_PLANNING_RULES in motir-ai/src/llm/treeGeneration.ts (the shipped planner). Sequence it after MOTIR-2089 to avoid colliding in the same region of both files; word it liftable verbatim into the mirror.
plan-rules.md gains the gate, adjacent to the existing precondition-verification rule, with this card's fixture named (the migrate_onboarding policy) and the claim-vs-pointer tell stated explicitly.SHARED_PLANNING_RULES mirror is a lift rather than a rewrite.docs/<slug>, no MOTIR-<n> in the PR title or branch (the motir-meta status-sync rule); the card reference goes in the PR body.motir-meta/prompts/plan-rules.md — the precondition-verification rule and the per-card gate checklist.motir-meta/notes.html — #33 (verify-don't-cite), the LESSON this generalises to plan time.motir-core/prisma/migrations/20260710042507_add_migrate_onboarding/migration.sql — the "no escape hatch" comment that disproves the criterion.motir-core/prisma/migrations/20260804180000_migrate_onboarding_system_admin_branch/migration.sql — the branch MOTIR-2082 had to add (PR #1830).