Filed while running MOTIR-3868 (PR #2451). The card was overwhelmingly correct and shipped; one clause of its first acceptance criterion was unbuildable as written.
buildChangesemits a change row fortargetRepoand one fortargetRepoRolewhen the patch carries either and the value differs from the target's
work_item.targetRepoRole does not exist. It was retired by Story MOTIR-2732 · MOTIR-3040 (ADR work-item-repository-set.md "Amendment 2026-08-18" §A3) on 2026-08-18 — eleven days before MOTIR-3868 was authored (2026-08-29T00:40:53Z).
Verified on origin/main @ c5d11f7f1, prisma/schema.prisma, where the retirement note sits in the column's own former place:
⚠️ targetRepoRole WAS HERE AND IS RETIRED … PlanItemProposedFields.targetRepoRole REMAINS: a plan still pins by role before any row exists; it is resolved to a reference at materialize instead of being copied onto the item.
So buildChanges(patch, target: WorkItem, …) has no from side to read for that key, and "differs from the target's" cannot be evaluated. The card's supporting sentence — "applyModify reads and applies both" — is true, and that is exactly what made the clause look verified: applyModify does read patch.targetRepoRole, but it applies it by resolving a repository reference (proposalRepoRef(name, role, refs)), never by writing a role onto the item.
The card verified the ENUMERATION and not the FIELD. Its "Measured on origin/main" table is a genuine, correct measurement of which patch keys buildChanges emits — the producer side. From that it inferred a symmetric consumer-side fact (the target has a value to diff against) that it never measured, on a field whose column had been deleted in the interim.
This is the re-measure the PREDICATE, not only the REF shape one field over: the ref was right, the command was right, the answer was right, and the sentence built on it named a second entity nobody checked. A criterion of the form "row X differs from the target's Y" asserts that Y exists on the target, and that is a schema claim owed a grep of schema.prisma — one command, and it was the same file the card's own retirement evidence would have come from.
Cost was small and the shape is what matters: the run had to stop, verify the retirement, choose a disposition (emit on key presence, from: null), amend the criterion on the record, and file this. A dispatched agent hitting the same clause would more likely have invented a from or dropped the role half silently.
plan-rules/phase-deepen.md's precondition-verification rule gains a limb: a criterion that compares a proposed value against "the target's" asserts the target CARRIES that field — verify the column/property exists on the entity, at the ref, before sealing the card. The producer-side enumeration being correct is not evidence for the consumer side.origin/main while the column its criterion diffed against had been dropped 11 days before — and states the one-command check (grep the model in prisma/schema.prisma, or the interface at the ref).motir-meta prompts/plan-rules/phase-deepen.md — the precondition-verification rule and its NEGATIVE / ENUMERATION limbsmotir-core prisma/schema.prisma — the targetRepoRole retirement note, in the column's former positionmotir-core lib/services/plansService.ts → applyModify / proposalRepoRef — what a role patch actually does now