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
[finding] SqlDriver reads keys off caller objects through (obj as any) at 7 sites while 3 parameter types declare none of them — a class, not a third coincidence (after #4311 tenancy, #16570 indexes) #16711
The third key was found and measured by #16570's implementer (report 5577212574, out_of_scope_findings), deliberately not fixed. This seat then re-measured the whole class on the tree itself rather than relaying the count.
⛔ Filed unassigned and unlabelled, as an observation for triage. Grade deliberately not asserted.
Measured on origin/maina0856e3bf9
Read with git show origin/main:packages/drivers/driver-sql/src/sql-driver.ts (⛔ not a working tree — a checkout in that session was 100+ lines stale on this file).
Every (obj as any).<key> read in the file, enumerated:
line
key
inside
:9370
indexes
ensureShardTable
:9397
indexes
ensureShardTable
:9611, :9612
indexes
registerManagedObjectMetadata
:9800
lifecycle
initObjects — (obj as any).lifecycle?.storage
:9841
indexes
initObjects
:9916
indexes
initObjects
7 sites, 2 distinct keys. Positive control for the same instrument: as any). over the whole file = 12, so the grep is not returning everything it sees and a 0 would have been a reading.
The three parameter types that declare none of them:
⇒ the class is not "a type someone forgot to widen". It is one class disagreeing with itself about the shape of the same input, in both directions, twice.
⚠️PR #16710 (#16570) fixes the indexes half at :9611–:9612 only — it declares the key on the two public entry points and the shared helper and deletes that one cast. It leaves :9370, :9397, :9841, :9916 and the lifecycle read standing, correctly and deliberately: its dispatch fenced it to one key, and the filer of #16570 fenced that card away from adjacent work for the same reason.
Why this is a class and why the failure is silent
TypeScript's excess-property check fires on a fresh object literal and not on one bound to a variable first. So the same object is accepted or rejected depending only on where it is spelled:
awaitdriver.initObjects([{ ...bare,lifecycle: {storage: …}}]);// REJECTED — TS2353constwithLifecycle={ ...bare,lifecycle: {storage: …}};awaitdriver.initObjects([withLifecycle]);// ACCEPTED, and the read happens
⇒ the loud outcome (a compile error on a correct call) is the good one. The bad one is an author — or an AI reading the signature — concluding the key is not accepted and dropping it, at which point:
dropping indexes ⇒ a declared UNIQUE is never synced, and nothing says so;
dropping lifecycle ⇒ the ADR-0057 rotation policy is never armed, and nothing says so.
Both are decided at authoring time by a type that contradicts the runtime. #16570's most valuable sentence generalises to the whole class: every existing caller happens to bind a variable first, which is why the package typechecks today — the workaround is load-bearing and nobody wrote it down.
📌 Evidence that the workaround has already been noticed and written down once, found by #16570's implementer and re-checkable: packages/drivers/driver-sql/src/sql-driver-11794-richtext-text-family.test.ts:324-326 says "Hoisted (not an inline literal) … indexes rides through initObjects beyond its narrow parameter type". A second escape shape exists at sql-driver-15479-shadow-plain-unique-duplicates.test.ts:128 (an as any on the argument). ⇒ callers have been silently routing around these signatures for at least two cards' worth of history.
What is being asked, not asserted
Two shapes were considered. ⛔ Neither is a grade and neither is a decision this seat is entitled to make:
(B) one class card: sweep every parameter type on SqlDriver that receives a caller object list against the keys actually read off it, close the gaps in one pass, and add a gate so a fourth cannot appear silently.
#16570's implementer recommended B, and this seat finds the reasoning sound and worth quoting rather than paraphrasing:
the measured evidence is now identical three times over and the failure mode is the silent one, not the loud one: dropping lifecycle leaves ADR-0057 rotation unarmed exactly as dropping indexes leaves a UNIQUE unsynced. A gate is what stops the fourth; a fourth card does not.
⚠️ The counter-argument is on the record too and should be weighed, not dismissed: the branch is loud (TS2353), not silent, until an author drops the key. ⇒ the whole grade turns on how reachable "an author reads the signature and drops the key" is — and ⛔ no instance of that actually happening has been measured, so it should ⛔ not be counted as having occurred.
📌 Escalation trigger, written down: if anyone measures a real object that declared indexes or lifecycle and had it dropped — an unsynced UNIQUE, duplicate rows a schema forbids, or an unarmed rotation policy — this stops being a hygiene class and becomes a data-integrity defect.
Filed by the
domain:engineexecution PM seat because the #16570 triage note (5576225663) wrote the trigger for it in advance:The third key was found and measured by #16570's implementer (report
5577212574,out_of_scope_findings), deliberately not fixed. This seat then re-measured the whole class on the tree itself rather than relaying the count.⛔ Filed unassigned and unlabelled, as an observation for triage. Grade deliberately not asserted.
Measured on
origin/maina0856e3bf9Read with
git show origin/main:packages/drivers/driver-sql/src/sql-driver.ts(⛔ not a working tree — a checkout in that session was 100+ lines stale on this file).Every
(obj as any).<key>read in the file, enumerated::9370indexesensureShardTable:9397indexesensureShardTable:9611,:9612indexesregisterManagedObjectMetadata:9800lifecycleinitObjects—(obj as any).lifecycle?.storage:9841indexesinitObjects:9916indexesinitObjects7 sites, 2 distinct keys. Positive control for the same instrument:
as any).over the whole file = 12, so the grep is not returning everything it sees and a0would have been a reading.The three parameter types that declare none of them:
And in each case a sibling on the same class already declares the key that its neighbour hides:
indexesinitObjects/registerObjectMetadata/ensureShardTabledetectManagedDrift—indexes?: any[]at:11009lifecycleinitObjects(:9800)rotateShards—lifecycle?: anyat:9185⇒ the class is not "a type someone forgot to widen". It is one class disagreeing with itself about the shape of the same input, in both directions, twice.
indexeshalf at:9611–:9612only — it declares the key on the two public entry points and the shared helper and deletes that one cast. It leaves:9370,:9397,:9841,:9916and thelifecycleread standing, correctly and deliberately: its dispatch fenced it to one key, and the filer of #16570 fenced that card away from adjacent work for the same reason.Why this is a class and why the failure is silent
TypeScript's excess-property check fires on a fresh object literal and not on one bound to a variable first. So the same object is accepted or rejected depending only on where it is spelled:
⇒ the loud outcome (a compile error on a correct call) is the good one. The bad one is an author — or an AI reading the signature — concluding the key is not accepted and dropping it, at which point:
indexes⇒ a declared UNIQUE is never synced, and nothing says so;lifecycle⇒ the ADR-0057 rotation policy is never armed, and nothing says so.Both are decided at authoring time by a type that contradicts the runtime. #16570's most valuable sentence generalises to the whole class: every existing caller happens to bind a variable first, which is why the package typechecks today — the workaround is load-bearing and nobody wrote it down.
📌 Evidence that the workaround has already been noticed and written down once, found by #16570's implementer and re-checkable:
packages/drivers/driver-sql/src/sql-driver-11794-richtext-text-family.test.ts:324-326says "Hoisted (not an inline literal) …indexesrides throughinitObjectsbeyond its narrow parameter type". A second escape shape exists atsql-driver-15479-shadow-plain-unique-duplicates.test.ts:128(anas anyon the argument). ⇒ callers have been silently routing around these signatures for at least two cards' worth of history.What is being asked, not asserted
Two shapes were considered. ⛔ Neither is a grade and neither is a decision this seat is entitled to make:
lifecycle, same shape as driver-sql:initObjects/registerObjectMetadatastill omitindexesfrom a parameter type they read it through — the shape #4311 fixed fortenancy, one key over #16570 — the smallest change, but it records a third instance as a third coincidence and leaves the fourth to arrive the same way.SqlDriverthat receives a caller object list against the keys actually read off it, close the gaps in one pass, and add a gate so a fourth cannot appear silently.#16570's implementer recommended B, and this seat finds the reasoning sound and worth quoting rather than paraphrasing:
📌 Escalation trigger, written down: if anyone measures a real object that declared
indexesorlifecycleand had it dropped — an unsynced UNIQUE, duplicate rows a schema forbids, or an unarmed rotation policy — this stops being a hygiene class and becomes a data-integrity defect.Boundaries
initObjects/registerObjectMetadatastill omitindexesfrom a parameter type they read it through — the shape #4311 fixed fortenancy, one key over #16570 / PR fix(driver-sql): declare theindexeskeyinitObjects/registerObjectMetadataalready read #16710 — that card is fenced to one key on purpose, and widening a public signature has its own verification surface.initObjects/registerObjectMetadatastill omitindexesfrom a parameter type they read it through — the shape #4311 fixed fortenancy, one key over #16570 drew that line deliberately.sql-driver.tsis currently held bysumover a column that is NULL in every row of a group: driver-sql answersnull, the engine's in-memory aggregate tier answers0— same query, same rows, fork chosen by a driver capability bit #15546 (aggregate presentation,:1324/:8478–:8653), PR fix(driver-sql): declare theindexeskeyinitObjects/registerObjectMetadataalready read #16710 (:9600–:9760), driver-sql:findWithWindowFunctionsreturns storage forms — a declared boolean answers1and an object field answers JSON text wherefind()answerstrueand the parsed object #16609 (findWithWindowFunctions,:8961) and PR feat(driver-sql): the read door presents datetime values and audit stamps as canonical ISO-Z text on every dialect (#13973, B1 narrow) #16619 (read-presentation helper definitions,:12874/:12901/:16655). This class's surface (:9356–:9931, plus:11009and:9185as the declaring siblings) overlaps PR fix(driver-sql): declare theindexeskeyinitObjects/registerObjectMetadataalready read #16710's region ⇒ whatever shape is chosen, it serialises behind that PR. ⛔ Not a reason to hurry it.origin/maina0856e3bf9and will drift — ⛔ 按符号重新推导.