Observation while working #8570 (PR #8633). Filed unassigned; nobody is on it. Not a defect in that PR — its own double calls assertEngineDeleteDispatch explicitly.
What I measured
check-engine-double-contract's discovery cannot see an engine double whose write verb is wrapped in a call — the vi.fn(...) spelling. implOf (scripts/check-engine-double-contract.mjs:353) returns the function only for a method, a FunctionExpression or an ArrowFunction:
if(ts.isPropertyAssignment(member)){constinit=member.initializer;if(init&&(ts.isFunctionExpression(init)||ts.isArrowFunction(init)))returninit;returnnull;}delete: vi.fn(async (o, opts) => …) is a CallExpression, so implOf answers null, consider() returns before the sibling and shape tests, and the double is never discovered. It is therefore neither pinned nor carried in scripts/engine-double-contract.baseline.json — it is simply absent from both sides of a ledger that is otherwise reconciled in both directions.
Confirmed on two real files rather than inferred: packages/metadata-protocol/src/protocol.batch-row-driver-text.test.ts and protocol.batch-row-http-status.test.ts each declare an engine double with insert / update / delete / findOne / transaction, all as vi.fn(async …), and both are absent from the gate's pinned listing and from the baseline while the run reports OK — 213 pinned, 133 in the DEBT ledger, 2 exempt.
Population, as an upper bound rather than a verdict: grep -rln "delete: vi\.fn\|update: vi\.fn" --include=*.test.ts packages/ matches 168 files. I did not classify how many of those are engine-shaped (≥2 engine siblings + isEngineVerbShape) versus driver or repository doubles, which is the measurement this card wants.
Why it is worth recording
The gate's own header names this failure mode: "a discovery that silently stops matching makes this script report OK while reading nothing" — which is why it asserts DISCOVERED is non-zero. That invariant catches a scan that breaks entirely; it cannot catch a scan that quietly skips one spelling, and vi.fn is the spelling most reached for when a test wants to assert call counts on the double it just wrote. Each skipped double is exactly what the gate exists to prevent: a fake free to accept a call ObjectQL.delete / ObjectQL.update refuses, on the paths a double was introduced for.
Scope if picked up
Teach implOf to unwrap a call whose sole function argument is the implementation (the vi.fn(fn) / vi.fn(async …) shape), then re-run: newly discovered doubles either pin or land in the baseline as a first measurement of a set the scan could not previously reach — the same act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the update slice first landed. Both precedents are in the script's own comments and both say plainly that a first measurement is not a raised ratchet. Whoever takes it should say which it is in the entry note, and fix rather than ledger anything cheap to pin.
Generated by Claude Code
Observation while working #8570 (PR #8633). Filed unassigned; nobody is on it. Not a defect in that PR — its own double calls
assertEngineDeleteDispatchexplicitly.What I measured
check-engine-double-contract's discovery cannot see an engine double whose write verb is wrapped in a call — thevi.fn(...)spelling.implOf(scripts/check-engine-double-contract.mjs:353) returns the function only for a method, aFunctionExpressionor anArrowFunction:delete: vi.fn(async (o, opts) => …)is aCallExpression, soimplOfanswersnull,consider()returns before the sibling and shape tests, and the double is never discovered. It is therefore neitherpinnednor carried inscripts/engine-double-contract.baseline.json— it is simply absent from both sides of a ledger that is otherwise reconciled in both directions.Confirmed on two real files rather than inferred:
packages/metadata-protocol/src/protocol.batch-row-driver-text.test.tsandprotocol.batch-row-http-status.test.tseach declare an engine double withinsert/update/delete/findOne/transaction, all asvi.fn(async …), and both are absent from the gate'spinnedlisting and from the baseline while the run reportsOK — 213 pinned, 133 in the DEBT ledger, 2 exempt.Population, as an upper bound rather than a verdict:
grep -rln "delete: vi\.fn\|update: vi\.fn" --include=*.test.ts packages/matches 168 files. I did not classify how many of those are engine-shaped (≥2 engine siblings +isEngineVerbShape) versus driver or repository doubles, which is the measurement this card wants.Why it is worth recording
The gate's own header names this failure mode: "a discovery that silently stops matching makes this script report OK while reading nothing" — which is why it asserts
DISCOVEREDis non-zero. That invariant catches a scan that breaks entirely; it cannot catch a scan that quietly skips one spelling, andvi.fnis the spelling most reached for when a test wants to assert call counts on the double it just wrote. Each skipped double is exactly what the gate exists to prevent: a fake free to accept a callObjectQL.delete/ObjectQL.updaterefuses, on the paths a double was introduced for.Scope if picked up
Teach
implOfto unwrap a call whose sole function argument is the implementation (thevi.fn(fn)/vi.fn(async …)shape), then re-run: newly discovered doubles either pin or land in the baseline as a first measurement of a set the scan could not previously reach — the same act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when theupdateslice first landed. Both precedents are in the script's own comments and both say plainly that a first measurement is not a raised ratchet. Whoever takes it should say which it is in the entry note, and fix rather than ledger anything cheap to pin.Generated by Claude Code