Planning bug: a bug card's error count was measured against a stale generated Prisma client — 175 phantom errors, 1 real
What the card claimed
MOTIR-4047, authored 2026-08-31: "tsc --noEmit fails on origin/main — 11 errors", with ten of them listed as TS7053 / TS18048 and characterised as "a lookup table that is not total over its key union". It even carried a reproduction, on a clean origin/main worktree, which is the part that makes this worth a card.
What is true
One error. The ten TS7053s did not exist.
| measurement | errors |
|---|---|
origin/main + the generated/prisma the repro COPIED IN | 175 |
origin/main + prisma generate at its own schema | 1 |
CI's own TypeScript job | 1 |
The mechanism
The reproduction did the hard part right — a fresh worktree at origin/main, no branch, no merge — and then, to avoid a two-minute pnpm install, symlinked a sibling worktree's node_modules and copied its generated/prisma. That client had been generated before MOTIR-1789's migrations, so it did not carry DispatchRun* at all.
The consequences are not what a reader expects from "a stale client":
DispatchRunStatus,DispatchEventKind,DispatchCardDispositionresolve to nothing, degrade toany, and every lookup indexed by one raisesTS7053— undernoImplicitAny, an index-signature error, which reads as a lookup-table defect rather than a missing import;- the errors cluster in exactly the files that legitimately use those types, so the distribution looks like a coherent finding about one story's code;
- and
TS2305/TS2339on the repositories — the errors that would have named the real cause — were below thehead -12the card's author read.
So the artefact is not noisy. It is a plausible, well-shaped, wrong diagnosis, and it survived being written up with a reproduction attached.
Why it is a PLANNING bug and not just a slip
The card was authored to be picked up by somebody else. Its acceptance criteria told that person to make ten lookup tables total over their key unions — work that did not exist — and two of its five criteria were void on arrival. A card is a set of instructions, and an instruction derived from a contaminated measurement is a defect in the plan whatever the code does.
The near-miss worth naming: the fix agent regenerated the client because the error COUNT disagreed with the card (175 vs 11), not because it doubted the diagnosis. Had the truncation been at 175 instead of 11, the two numbers would have agreed and the phantom errors would have been "fixed".
The rule this is about
plan-rules/phase-deepen.md's ENUMERATION limb already says a card counting a population owes the ref the count was taken on. This card gave a ref — origin/main at e2f08aeb1 — and the ref was right. The ref was not the variable; the TOOLCHAIN was. A tsc reading depends on generated, uncommitted artefacts that a ref cannot pin, and git worktree add does not produce them.
The generalisation, which is what a rule change would have to say: when a card's number comes from a build tool, the card owes the tool's own preconditions, not only the ref — for this repository, pnpm install and prisma generate, or simply the number CI reported, which was correct and freely available the entire time.
Fix
Decide whether this becomes a bar in plan-rules/phase-deepen.md's enumeration limb (a count from a build tool cites the tool's setup, or cites CI) or stays at the lesson tier. Prefer CI's number where CI produces one — it is measured on a clean runner with the real setup, and it was one command away.
Evidence
motir-coreorigin/maine2f08aeb1; the correcting run is PR #2490prisma/schema.prisma—output = "../generated/prisma", andgenerated/is not committed- The full correction, with the three-row table, is a comment on MOTIR-4047
- Sibling card, same incident, opposite half: MOTIR-4050 — the repository CONTROL for the merge-order class this was found inside