You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
IDataDriver declares no aggregate, yet the engine dispatches to driver.aggregate through as any — the one engine-reached driver verb with no signature to match #14345
Found while typing the recording driver double in packages/objectql/src/engine-filter-array-lowering.test.ts (#14117 / PR #14344). ⛔ Recording only — no severity asserted, routing is triage's. Not fixed there: out of that card's fence, and it moves a public contract.
Measured at 909a4417
packages/objectql/src/engine.ts reaches the driver's aggregation path by duck-typing, through a cast that erases the call:
packages/spec/src/contracts/data-driver.ts declares noaggregate member on IDataDriver — required or optional. Grep for aggregate in that file returns nothing.
Why this is not just the capability convention
The duck-typing itself is deliberate and documented: packages/spec/src/data/driver.zod.ts states the rule for DriverCapabilities — "aggregation on typeof driver.aggregate === 'function' … Do not add a boolean here for behaviour that a method's presence already decides". That rule is about capability bits, and it is right. It says nothing about whether the method should be declared.
Every other engine-reached optional verb IS declared: updateMany?, deleteMany?, explain?, syncSchemasBatch?, registerExternalObject?, registerObjectMetadata?, getSchemaSyncStats?, introspectSchema?, reclaimSpace?, temporalFilterValue?, temporalFilterColumnSql?. aggregate is the only one reached by the engine with nothing to match against.
introspectSchema's own TSDoc in that file argues exactly this case for itself, and the argument transfers verbatim: a driver author implementing the interface "had no signature to mis-match against, so a column flag spelled isPrimary … compiled clean and surfaced only as a federated table whose records silently could not be located". Today an author can write aggregate(query, object) with the arguments swapped, or return the wrong row shape, and tsc has nothing to say — the engine's as any absorbs it and the result reaches applyHaving.
Consequence, stated narrowly
A custom driver's aggregate is unchecked in both directions: its parameters and its return.
⛔ No drift is claimed to exist today. In-repo drivers are fine. The claim is only that a drift here would not be caught.
⛔ What is NOT claimed
⛔ Not claimed the duck-typed dispatch is wrong. Presence-testing an optional member is the repo's stated convention and works.
⛔ Not claimed the capability schema needs a bit for this. driver.zod.ts rules that out explicitly and correctly.
⛔ Not claimed the engine's as any at that site must go. Declaring the member is the smaller move; whether the cast then narrows is a separate judgement.
⛔ No opinion offered on whether the declaration should be optional (matching the presence test) or required (matching the fact that four in-repo drivers implement it). That is the decision this card hands to triage.
Dedup — the channel fired, so this is a reading
One targeted semantic search returned 28 on-topic results. Nearest neighbours, all closed:
an as any hiding a wrong aggregation key in test fixtures — the consequence class, not this seam
No open card covers IDataDriver's missing aggregate declaration.
Related
#14117 / PR #14344 (where this was found) · #11493 / #11381 (the ruling that declared introspectSchema for this exact reason) · #12248 (same shape, engine side)
Found while typing the recording driver double in
packages/objectql/src/engine-filter-array-lowering.test.ts(#14117 / PR #14344). ⛔ Recording only — no severity asserted, routing is triage's. Not fixed there: out of that card's fence, and it moves a public contract.Measured at
909a4417packages/objectql/src/engine.tsreaches the driver's aggregation path by duck-typing, through a cast that erases the call:packages/spec/src/contracts/data-driver.tsdeclares noaggregatemember onIDataDriver— required or optional. Grep foraggregatein that file returns nothing.Why this is not just the capability convention
The duck-typing itself is deliberate and documented:
packages/spec/src/data/driver.zod.tsstates the rule forDriverCapabilities— "aggregation ontypeof driver.aggregate === 'function'… Do not add a boolean here for behaviour that a method's presence already decides". That rule is about capability bits, and it is right. It says nothing about whether the method should be declared.Every other engine-reached optional verb IS declared:
updateMany?,deleteMany?,explain?,syncSchemasBatch?,registerExternalObject?,registerObjectMetadata?,getSchemaSyncStats?,introspectSchema?,reclaimSpace?,temporalFilterValue?,temporalFilterColumnSql?.aggregateis the only one reached by the engine with nothing to match against.introspectSchema's own TSDoc in that file argues exactly this case for itself, and the argument transfers verbatim: a driver author implementing the interface "had no signature to mis-match against, so a column flag spelledisPrimary… compiled clean and surfaced only as a federated table whose records silently could not be located". Today an author can writeaggregate(query, object)with the arguments swapped, or return the wrong row shape, and tsc has nothing to say — the engine'sas anyabsorbs it and the result reachesapplyHaving.Consequence, stated narrowly
aggregateis unchecked in both directions: its parameters and its return.any— the shape the tsc-program work is trying to retire.⛔ What is NOT claimed
driver.zod.tsrules that out explicitly and correctly.as anyat that site must go. Declaring the member is the smaller move; whether the cast then narrows is a separate judgement.Dedup — the channel fired, so this is a reading
One targeted semantic search returned 28 on-topic results. Nearest neighbours, all closed:
query.objectat the driver boundary — the redundancyDriverQuerythen removedIDataEnginegaining declared optional members). Precedent for the class, on the other interfaceas anyhiding a wrong aggregation key in test fixtures — the consequence class, not this seamNo open card covers
IDataDriver's missingaggregatedeclaration.Related
#14117 / PR #14344 (where this was found) · #11493 / #11381 (the ruling that declared
introspectSchemafor this exact reason) · #12248 (same shape, engine side)