Found while fixing #6546 (PR #7261). Recorded, not fixed there — #6546's file surface is
packages/objectql/src/protocol-batch-atomic.test.ts only, and folding this in would have turned an
XS card into a 64-file sweep.
Observation
#6546 was one driver double authoring a capability key retired by #4634. The deletion was trivial;
the interesting half was why nobody noticed — the literal was annotated const driver: any, so it
was never compared against IDataDriver, and nothing in that file parses it through
DriverInterfaceSchema. With both channels off, the retiredKey(...) tombstone in
DriverCapabilitiesSchema had nothing to fire through.
That annotation is not unusual in this package. Measured on origin/main @ 0caf122:
|
files |
packages/objectql/src/**/*.test.ts with a driver-ish double annotated : any = |
64 |
…of which also spell supports: {} as any |
17 |
test files that reference IDataDriver at all |
14 |
What this is NOT
No retired bit is authored in any of them today, and no gate is red. A repo-wide sweep for
supports: literals spelling retired or invented keys (run as part of #6546) found nothing beyond
#6546's own instance, #4782's, and the two deliberate rejection fixtures
(packages/spec/src/data/driver.test.ts:317, packages/spec/src/data/datasource.test.ts:60), which
are correct as written. Every other literal is either {} or a live bit
(autonumber, batchSchemaSync, queryDateGranularity).
So this is observation-class, exactly like #6546: nothing a user hits, nothing broken.
Why it is still worth a line
The tombstone's stated design is that a retired key is authored-unwritable — "tsc rejects it at
the authoring site" is the first of the two channels driver.zod.ts names for it. Across these 64
files that channel is switched off, so the tombstone's protection currently rests entirely on the
second channel (a parse), which test doubles by definition rarely go through.
The concrete harm is the one #4782 and #6546 both name: mocks get copied. #6546's mock had
carried its retired bit since #4634 without anyone noticing, and it was found by reading, not by a
gate. The cost of the class is that the next such copy is equally invisible.
Measurement from #6546, for sizing
Retyping one double any → IDataDriver cost three stubs for interface members the tests never
reach (upsert, syncSchema, dropTable), and moved @objectstack/objectql's measured
TEST_DEBT count by zero (340 → 340, ceiling 355). One data point, not a trend — that double
was already close to interface-shaped, and the as any in 17 of the files above suggests some are
further away. Anyone picking this up should re-measure per file rather than extrapolate from one.
Note also that a naive sweep will trip TS2790 wherever a test does delete driver.<requiredMember>
to prove a method-presence gate; Reflect.deleteProperty(...) is the cast-free equivalent (#6546
used it).
Suggestion
Not obviously a single sweep. Plausible shapes, in increasing cost:
- Leave it, and retype opportunistically whenever a file is touched for another reason.
- Retype only the doubles that author a non-empty
supports — the ones where a capability key
could actually be spelled wrong — which is a much smaller set than 64.
- A gate that fails a driver double annotated
any, ratcheted against a measured baseline in the
style of check-engine-double-contract.
Filing without a recommendation; the sizing above is what I measured, not a plan.
Found while fixing #6546 (PR #7261). Recorded, not fixed there — #6546's file surface is
packages/objectql/src/protocol-batch-atomic.test.tsonly, and folding this in would have turned anXS card into a 64-file sweep.
Observation
#6546 was one driver double authoring a capability key retired by #4634. The deletion was trivial;
the interesting half was why nobody noticed — the literal was annotated
const driver: any, so itwas never compared against
IDataDriver, and nothing in that file parses it throughDriverInterfaceSchema. With both channels off, theretiredKey(...)tombstone inDriverCapabilitiesSchemahad nothing to fire through.That annotation is not unusual in this package. Measured on
origin/main@0caf122:packages/objectql/src/**/*.test.tswith a driver-ish double annotated: any =supports: {} as anyIDataDriverat allWhat this is NOT
No retired bit is authored in any of them today, and no gate is red. A repo-wide sweep for
supports:literals spelling retired or invented keys (run as part of #6546) found nothing beyond#6546's own instance, #4782's, and the two deliberate rejection fixtures
(
packages/spec/src/data/driver.test.ts:317,packages/spec/src/data/datasource.test.ts:60), whichare correct as written. Every other literal is either
{}or a live bit(
autonumber,batchSchemaSync,queryDateGranularity).So this is observation-class, exactly like #6546: nothing a user hits, nothing broken.
Why it is still worth a line
The tombstone's stated design is that a retired key is authored-unwritable — "tsc rejects it at
the authoring site" is the first of the two channels
driver.zod.tsnames for it. Across these 64files that channel is switched off, so the tombstone's protection currently rests entirely on the
second channel (a parse), which test doubles by definition rarely go through.
The concrete harm is the one #4782 and #6546 both name: mocks get copied. #6546's mock had
carried its retired bit since #4634 without anyone noticing, and it was found by reading, not by a
gate. The cost of the class is that the next such copy is equally invisible.
Measurement from #6546, for sizing
Retyping one double
any→IDataDrivercost three stubs for interface members the tests neverreach (
upsert,syncSchema,dropTable), and moved@objectstack/objectql's measuredTEST_DEBTcount by zero (340 → 340, ceiling 355). One data point, not a trend — that doublewas already close to interface-shaped, and the
as anyin 17 of the files above suggests some arefurther away. Anyone picking this up should re-measure per file rather than extrapolate from one.
Note also that a naive sweep will trip
TS2790wherever a test doesdelete driver.<requiredMember>to prove a method-presence gate;
Reflect.deleteProperty(...)is the cast-free equivalent (#6546used it).
Suggestion
Not obviously a single sweep. Plausible shapes, in increasing cost:
supports— the ones where a capability keycould actually be spelled wrong — which is a much smaller set than 64.
any, ratcheted against a measured baseline in thestyle of
check-engine-double-contract.Filing without a recommendation; the sizing above is what I measured, not a plan.