docs(driver-sql): re-anchor the dead tracker citations to the commits and ADR that decided them (stage 4 of #20595) - #21357
Conversation
… and ADR that decided them (stage 4 of #20595) Comment and docblock prose only, in ruling C+D's form C: every comment site in packages/drivers/driver-sql that cited a tracker number answering 404 (39 numbers, 291 sites on 287 lines), plus the dead comment id 5448627494 (2 lines), now cites the ADR when one records the decision, otherwise the commit in this repository that made it. Every file keeps its line count; no code token, string literal or numeric literal moves; no tracker number is added. Claude-Session: https://claude.ai/code/session_017xfMoEjKUuSh2xYB8sCozp Co-authored-by: Claude <noreply@anthropic.com>
…iver-sql-citations
57 of the 122 rewritten non-test lines ship verbatim in dist (index.d.ts, index.d.mts, index.js, index.mjs); a base-text rebuild differs in those 4 of 6 dist files and a restored-head rebuild is byte-identical. Claude-Session: https://claude.ai/code/session_017xfMoEjKUuSh2xYB8sCozp Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 30 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 11 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin e90bf96ffc3bfa55638dc816bcae166067b64175 && git checkout e90bf96ffc3bfa55638dc816bcae166067b64175
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 96b12b589ff864c2500e231f0b31b10be69d2c54 fad95aff731848bc407b300da2067aadc0c7a475 && git checkout -B drift-repro 96b12b589ff864c2500e231f0b31b10be69d2c54 && git merge --no-ff fad95aff731848bc407b300da2067aadc0c7a475
node scripts/docs-audit/affected-docs.mjs --json 96b12b589ff864c2500e231f0b31b10be69d2c54
|
Contract reviewServed-tier: Inputs read, and nothing else: card #20595 (body and all seventeen comments: the two lane pointers, the post-landing census ① Derived judgmentsDiff of record. The merge base of the head with Accept set and public surface: nothing moves. Judged RIGHT, on this reading of the diff text: every Sampled hunks: all 291 pairs were read as their Anchors. The The The #11374 split. The #17590 sites reworded in tense. The dead comment id #15041 to ADR-0104's 2026-09-05 addendum (7 sites, plus the changeset). No new tracker number; live numbers stayed. For every pair, the numbers on the Rewritten sentences stay true. Each sentence that credits a commit with a ruling, a measurement, a review or a note was matched against that commit: Reach into ② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Part of #20595
Clause-②: no
What changed
Stage 4 of the
domain:enginelane of the dead-citation sweep:packages/drivers/driver-sql/**, comment and docblock prose only, per the claim (5946343111). Stages 1 to 3 landed asa7d9768ec,d150c3039and4bf4e7e70; #20595 stays open for the next stage.Every comment or docblock site in the package that cited a tracker number answering 404 is rewritten in ruling C+D's form C (record
5749154545on #19123): the ADR when one records the decision, otherwise the commit in this repository's history that made it. That is 291 sites on 287 lines in 54 files, covering 39 numbers, plus one dead comment-id citation on two lines:src/): the wholeallocated-but-absentpopulation of the gate's own census in this package at the base, the slash-joined#7737/#10629and#14079/#15683/#17343from the post-landing census (5923084795, now atsql-driver.ts:12236and:16167) included. That census's third driver-sql site, the URL-spelled#17590at:3933, left the file in58a77dbde2before this base;src, 5 more it reads as dead elsewhere in the repository, and 8 it never judges (they stand only in test files), which the board and a single read each settle;5448627494(on [finding]AGGREGATION_ROWShas no boolean column, so the cross-driver aggregation conformance family cannot see a boolean aggregand on any face #11152, which is live), on two test-comment lines.Anchors: 38 numbers by commit, 1 by ADR (ADR-0104's 2026-09-05 addendum), 0 by words alone; the comment id by commit. 16 numbers reuse the anchor another lane or stage already measured for them, 23 were measured here (one of them split across two commits), and the comment id was measured here. 39 distinct shas.
Only comments changed. Every file keeps its line count (291 lines out, 291 in, plus the changeset), so no line citation into any of them moves. No code token moves (the guard below). No citation number is added: on every changed line, the numbers on the new text are a subset of those on the old, and the diff-scoped gate judged the 10 citations left on changed lines: all 10 resolve.
A
patchchangeset: 57 of the 122 rewritten non-test lines are in the publisheddist(the.d.tskeeps JSDoc on exported members, and esbuild keeps some comments in the JS), anddistis not byte-identical with the base text (see Changeset).Census:
driver-sql, before and afterInstrument (A1). The gate's own
node scripts/check-issue-citations.mjs --census --json, read-only and unchanged. The count is itsallocated-but-absentfindings underpackages/drivers/driver-sql/.allocated-but-absent222ecc27f, run 05:52:18Z to 05:55:43Z286316ebd, run 06:17:50Z to 06:21:10ZThe whole-repo drop is 126, and the two finding sets differ by exactly the 126 rows of this package, removed; none was added.
resolves(34,789),resolves-as-pull-request(2,378) andcross-repo-unjudged(1,155) did not move. The card's 128 was taken atf11b5f20a2with the older extractor; the base here reads 126. The head's later commits are a merge ofmainthat touches no file underpackages/drivers/driver-sqland the changeset (outside the census surface).Supplementary instrument, the whole package. The census reads neither test files nor strings nor files outside
src. A second reading runs the gate's own exportedextractCitations(whole-file and comment-prose projections) over every tracked file in the package (238.ts,package.json,tsconfig.json,README.md,CHANGELOG.md,LICENSE), and classifies each citation with the gate'sclassifyCitationagainst one board enumerated by the gate'senumerateBoard(192 pages, frontier #21346, 19,167 records, 05:56:41Z to 05:59:55Z). Every one of the 39 numbers in the population was then read on its own over the issues endpoint: all 39 answer 404, and the lit controls#5286and#12624answer 200.222ecc27f286316ebdThe drop of 291 citations is exactly the rewritten sites, and the live counts did not move (src comment: 1,352 resolve, 24 as pull requests; test comment: 1,545 and 69). A third, raw reading (every
#followed by 2 to 6 digits, whatever surrounds it) counts 4,939 before and 4,654 after: a drop of 285, which is the 291 less the 6 URL-spelled sites that carry no#.Comment ids. Nine distinct comment-id citations stand on 19 sites in this package (
CHANGELOG.mdaside). Each was read over the issue-comments endpoint:5448627494answers 404 (it was a comment on #11152, which itself answers 200), and the other eight answer 200 (5302931807,5404884704,5556979386,5618311630,5861435168,5865693155,5881556735,5934879010; control5946343111, 200). So the one dead id is in the population.5642107998, the ruling recorde04a0aff2's message names for #17590, also answers 404; it is not cited in this package.Per-number table
srccounts census sites,testcounts test-comment sites. Every sha below matches exactly one commit (git rev-parse --disambiguate, count 1) and is an ancestor of the merge base04f0cc499(git merge-base --is-ancestor, exit 0 for all 39 shas; the clone is not shallow). The+lines introduce exactly these 39 nine-hex spans and no other. The message or the diff of each one names the number it replaces: 23 in the message and the diff, 11 in the diff alone (#11065,#11374ford0e3a885b,#12978,#12999,#13015,#13324,#14438,#14628,#16649,#16711,#17586), 3 only in the subject's squash suffix (#6076,#14434,#17876, where the dead number was that pull request's own and the commit is its squash), and one exception,#10629, explained under Wordings to check.f6fa22ce1's diff names the comment id three times. Where a sentence credits a ruling, a measurement, a review or a note to the number, the anchor's own message or diff carries it (checked per site; the ones that needed a reworded sentence are listed below).sourcesays whether another lane or stage already used this anchor for this number (reused) or it was measured here (measured).#6075d367f03d6DriverQuery#60766513c1749IDataDriver's query parameter becomesDriverQuery(that pull request's squash)#87787901b2dd2tenancy.organizationField#88234dfa369a9#95428bbf45947#10165801296050ttl.onlyWhenrow filter with the canonical null predicate#10629199ec4712#108367ab286e44ttl.onlyWhen$nullsuite#1106520950404c#11067479fba50dupdated_atwhen the driver never ran DDL#11374d0e3a885b+107bb4ba4varchar(maxLength)for a text field a declared index keys on / carry an over-long UNIQUE index on a hash-shadow column, the route the 2026-08-24 ruling chose#123804045b954dField.jsoncodec injective, one encoding across all three dialects#12978e4902d2b9maxLengthon the keyed text columns of thesys_notification_*objects#12998df1c75c4b#12999ebcc34e89#13015cd1348802#132796a180e42ddriver-error-classification.test.ts#133244cda78c9b#1443493940d492IDataDriver.update()(that pull request's squash)#144382200f8ec8update()publishes the contract's record-or-null, notany(the squash of PR #15280)#146286392b9c2brawDriver()#1490261821e54c#15041sys_fileid; the step's abort requirement, its SQL sketch, and the generator as the side that does not move#16570b72226f48indexeskeyinitObjects/registerObjectMetadataalready read#1660978bc4ad58findWithWindowFunctionspresents its rows like every other read door, and the alias-collision ruling#1661945cfa1b88#16649613bfbd3ddoor: 'none'codes, re-registeringMONGODB_MULTI_TENANT_UNSUPPORTED#166575a95b0e93causefor operator-facing records#167117862fb711#167290f38ab084syncSchemare-registration#1734382cb69fedmultiple: trueboolean column keeps its$containsmembership filter#17586d46deba19#17590e04a0aff2$containson a JSON column as a per-dialect MEMBERSHIP test; its message records the director's 2026-09-12 Ruling A#176397c2c5aedddistinct()backend fault#17690be5c60291IDataDriverdoors publish their declared return type#178579ccc4179edistinct()column to the clause the caller named#17876be5c60291ContainsAnydetector#17879eb9334915ContainsAnyphantom-leg sweep across eight door pins#1797047e6601c5ContainsAny's distributivity so union-shaped doors assert5448627494f6fa22ce1Wordings to check
Most rewrites swap a tag in place (
[#N]to[commit SHA],(#N)to(commit SHA),#N's Xtocommit SHA's X,PR #Nto its squash commit, a URL@seeto@see commit SHA), the form the landed stages use. These say more than the tag:#10629, one site (sql-driver.ts:12236): 「the same ruling external-datasource-federated-read: federated read returns empty — the external object→remote-table mapping never registers (boot ordering) #7737/[finding] 15 more PASSING@objectstack/runtimetests print the samerefused a read onfeature — 134 lines after #10380 quiets its two, led bynotifications.hono.integration.test.ts(52) #10629 already made for FEDERATED objects」 became 「the same ruling external-datasource-federated-read: federated read returns empty — the external object→remote-table mapping never registers (boot ordering) #7737 already made for FEDERATED objects (commit 199ec47)」, stage 3's judged form (contract review5943182373):199ec4712is external-datasource-federated-read: federated read returns empty — the external object→remote-table mapping never registers (boot ordering) #7737's fix and its message states the ruling; it names external-datasource-federated-read: federated read returns empty — the external object→remote-table mapping never registers (boot ordering) #7737, not [finding] 15 more PASSING@objectstack/runtimetests print the samerefused a read onfeature — 134 lines after #10380 quiets its two, led bynotifications.hono.integration.test.ts(52) #10629.#11374, split by subject. 20 sites describe the keyed-text rule (varchar(maxLength)for a field a declared index keys on, the shard path,boundedObject(), the named refusal):d0e3a885b, the driver commit whose diff names driver-sql: the platform-objects schema does not sync onto MySQL — unbounded string fields become TEXT, which MySQL refuses to index #11374 fourteen times and introducedexplainUnkeyableTextColumnandboundedObject(). 3 sites credit 「the maintainer's 2026-08-24 ruling」 that chose the hash route:107bb4ba4, whose message moves 「driver-sql: the platform-objects schema does not sync onto MySQL — unbounded string fields become TEXT, which MySQL refuses to index #11374's refusal pins」 and records 「the ruling deliberately replaced」 and 「the prefix constraint the ruling rejected」. Its message does not carry the date, so those sites keep their date and read 「landed as commit 107bb4b」 / 「recorded in commit 107bb4b」 (stage 1's#9741precedent). Other lanes anchored driver-sql: the platform-objects schema does not sync onto MySQL — unbounded string fields become TEXT, which MySQL refuses to index #11374 to their own packages' bound declarations (e4902d2b9,f64668d3c,3954fb7df), a different subject; the driver's own rule isd0e3a885b.#15041, seven sites: 「the [finding] FILE_REFERENCE_TYPES disagree about their column:driver-sqlputs file/image/avatar/video/audio inJSON_COLUMN_TYPES,packages/cligenerate.ts gives themVARCHAR(2048)— and neither side is obviously the one that should move #15041 addendum」 / 「the ruling on [finding] FILE_REFERENCE_TYPES disagree about their column:driver-sqlputs file/image/avatar/video/audio inJSON_COLUMN_TYPES,packages/cligenerate.ts gives themVARCHAR(2048)— and neither side is obviously the one that should move #15041」 became 「the ADR-0104 2026-09-05 addendum」 / 「the ruling in ADR-0104's 2026-09-05 addendum」, the spelling stage 3 and the cli lane used. The addendum names [finding] FILE_REFERENCE_TYPES disagree about their column:driver-sqlputs file/image/avatar/video/audio inJSON_COLUMN_TYPES,packages/cligenerate.ts gives themVARCHAR(2048)— and neither side is obviously the one that should move #15041 as its provenance and carries each claim the sites make: the abort-on-the-first-non-JSON-string requirement, theUSING (col #>> '{}')sketch, and 「the driver is the side that moves」 for the generator.sql-driver-15989-file-family-bare-id.test.ts:7keeps the maintainer's verbatim quote untouched (it carries no#).sql-driver-11635-boolean-aggregand-answers.test.ts:9,sql-driver-11782-boolean-row-read-presentation.test.ts:36-:37): 「applied in its comment 5448627494」 became 「landed as commit f6fa22c」.f6fa22ce1applies 「the 2026-08-28 maintainer ruling (option A, superseding [Decision]min/maxover a boolean aggregand: pin the cross-driver JSON answer —0/1(SQL) vsfalse/true(both in-memory faces) #11249's false/true)」 to driver-sql's result presentation, and its diff names the comment id. [finding]AGGREGATION_ROWShas no boolean column, so the cross-driver aggregation conformance family cannot see a boolean aggregand on any face #11152 stays.#17590where it was written while the card was open (the17639and17857suites,sql-driver.ts:11060,sql-driver-17586-…test.ts:101): those sentences park the json-columndistinct()question 「with driver-sql: the $contains MEMBERSHIP spelling on any multi-valued / JSON column is a DATABASE_ERROR 500 on live PostgreSQL (SQLSTATE 42883, operator does not exist: json ~~ text) — it has only ever been executed on SQLite #17590」.e04a0aff2closed that card with Ruling A on$containsonly, so a bare swap would credit it with adistinct()verdict it never made. They now read 「the card commit e04a0af closed, which owned the sibling divergence」, 「if a card after commit e04a0af rules that a json column should ANSWER a distinct read」 (both retirement clauses), 「the ruling commit e04a0af records cannot move it」, 「that question belonged to the card commit e04a0af closed」, 「Nothing here touches the card commit e04a0af closed」 and 「the divergence commit e04a0af ruled on the filter side」.sql-driver-17639-distinct-fault-envelope.test.ts:206is the one changed line that carries no number: its verb (「owns」 to 「owned」) had the number on:205as its subject.updated_atis never refreshed on a deployment that skips boot schema sync —tablesWithTimestampsis also only filled by DDL #11067」 became 「## Not the defect commit 479fba5 fixed」; 「driver-sql: drift differ reads a healthy #11627 hash-shadow UNIQUE as destructive recreate_index drift, and the proposed remedy would drop the constraint #13015 was the price of the split」 became 「The defect commit cd13488 fixed was the price of the split」; 「driver-sql: amultiple: trueBOOLEAN column loses its$containsmembership filter — the #14079 type-gate compiles it to1 = 0, where the same shape on amultiple: truenumber keeps its GLOB #17343: amultiple: trueBOOLEAN column lost …」 became 「The defect commit 82cb69f fixed: …」; 「The defect that produced the table ([finding] driver-sql's SQLite json codec is not round-trip faithful for a string whose content is valid JSON — '123' reads back as a number, and Postgres does not agree #12380)」 became 「(fixed in commit 4045b95)」 and 「let [finding] driver-sql's SQLite json codec is not round-trip faithful for a string whose content is valid JSON — '123' reads back as a number, and Postgres does not agree #12380 survive」 became 「let the defect commit 4045b95 fixed survive」; 「family as driver-sql:updated_atis never refreshed on a deployment that skips boot schema sync —tablesWithTimestampsis also only filled by DDL #11067 / driver-sql:updateMany()never stampsupdated_at, andupsert()'s merge branch does not advance it on Postgres/MySQL — on every deployment, DDL or not #11176 / driver-sql:updateMany()bypassesformatInput/applyWriteColumnMap— json and array writes are refused, a federatedcolumnMapobject's bulk update names a column that does not exist, and SQLite datetime writes land non-canonical #11223」 became 「family as driver-sql:updateMany()never stampsupdated_at, andupsert()'s merge branch does not advance it on Postgres/MySQL — on every deployment, DDL or not #11176 / driver-sql:updateMany()bypassesformatInput/applyWriteColumnMap— json and array writes are refused, a federatedcolumnMapobject's bulk update names a column that does not exist, and SQLite datetime writes land non-canonical #11223 / the one commit 479fba5 fixed」.pre-/post-spellings: 「a pre-driver-sql (MySQL): the #11627 hash shadow drops the NULL-safe organization key part — a shadow-carried org-scoped UNIQUE reintroduces #5030's NULL-org zero-constraint #12998 shadow」 became 「a shadow from before commit df1c75c」 (and the same shape for#12380and#17590); 「post-driver-sql (MySQL): the #11627 hash shadow drops the NULL-safe organization key part — a shadow-carried org-scoped UNIQUE reintroduces #5030's NULL-org zero-constraint #12998」 became 「since commit df1c75c」; 「The pre-driver-sql (MySQL): the #11627 hash shadow drops the NULL-safe organization key part — a shadow-carried org-scoped UNIQUE reintroduces #5030's NULL-org zero-constraint #12998 shadow over RAW columns」 became 「The older (before commit df1c75c) shadow over RAW columns」.45cfa1b88is that pull request's squash, and its message records FINDING-1 to FINDING-3 and the hand-made TEXT-affinity measurement. 「the [finding] 类型级 pin 家族的 IsAny 探测器看不见嵌套的 any —— 规定红两次的门只红一次,已落地的 #17689 pin 上实测,另有 10 个同族文件未测 #17879 report」 became 「commit eb93349's message」 (two sites); that message records that both repair candidates were measured.#16649(dialect-emission-refusal.ts:66): 「a removal spec: register the 14 remainingdoor: 'none'(boot-refusal) codes that ship indist— the rest of the #16404 class after #16449 #16649 reversed」 became 「a removal that commit 613bfbd reversed」.613bfbd3dre-registeredMONGODB_MULTI_TENANT_UNSUPPORTED「under the ruling」; the runtime lane's44c917a47is spec: register the 14 remainingdoor: 'none'(boot-refusal) codes that ship indist— the rest of the #16404 class after #16449 #16649's vocabulary-gate half, a different subject.#14628(live-dialect-matrix.testkit.ts:451,sql-driver-datetime-mysql-storage.test.ts:57):6392b9c2bbudgeted the eighth live-cell hook and wrote the(#14628)line itself; the seven before it were13b520069(PR test(driver-sql): give the seven unconditionally-live hooks an explicit 60_000 budget #14629), which cites driver-sql: 7 unbudgeted LIVE-cell hooks outside #14100, and a measured correction — hooks inherit hookTimeout (10000ms), not testTimeout (5000ms) #14213, the number kept beside it.InMemoryDriver.update()returnsnullfor a missing id, whichIDataDriver.update()'s declared return type forbids — hidden for the life of the code by an inferredany#13878 / PR feat(spec): declare the not-found arm on IDataDriver.update() and un-mask driver-memory's published update/upsert types #14434」 became 「[finding]InMemoryDriver.update()returnsnullfor a missing id, whichIDataDriver.update()'s declared return type forbids — hidden for the life of the code by an inferredany#13878 / commit 93940d4」; 「ContainsAny(fix(driver-sql,driver-turso): eight more IDataDriver doors publish their declared return type #17876)」 became 「(commit be5c602)」, the squash that installed it; 「[finding]SqlDriver.update()keeps an explicitPromise[any]while returningnullon a miss — the same published-type mask #14434 removed from driver-memory, inherited by TursoDriver and SqliteWasmDriver #14438 (PR feat(driver-sql,driver-turso):update()publishes its honest type — the contract'sRecord[string, unknown] | null, notany(#14438) #15280)」 became 「Commit 2200f8e (PR feat(driver-sql,driver-turso):update()publishes its honest type — the contract'sRecord[string, unknown] | null, notany(#14438) #15280)」, the live pull-request number kept beside its squash as a convenience.warn, but AGENTS.md's degradation rule names DDL-that-did-not-run aserror#9609]」 became 「[commit 8bbf459, driver-sql: the boot widening's swallowed failure logswarn, but AGENTS.md's degradation rule names DDL-that-did-not-run aserror#9609]」; 「[spec] IDataDriver 的 query 参数要求QueryAST.object与第一实参重复 —— 下游被迫as any(20 处实测),提议 Omit/optional 化 #5181/[finding][drivers] 五个驱动的find/count/…仍声明query: QueryAST,而调用方已可省略object—— 双变让它编译,但声明开始说谎 #6075」 became 「[spec] IDataDriver 的 query 参数要求QueryAST.object与第一实参重复 —— 下游被迫as any(20 处实测),提议 Omit/optional 化 #5181 and commit d367f03」; 「driver-sql: the platform-objects schema does not sync onto MySQL — unbounded string fields become TEXT, which MySQL refuses to index #11374/driver-sql (MySQL): full-value UNIQUE on >768-char token columns is inexpressible on utf8mb4 — hash-shadow-key route for the four ruled cases (C half of the #11374 ruling) #11627 exist to end」 became 「driver-sql (MySQL): full-value UNIQUE on >768-char token columns is inexpressible on utf8mb4 — hash-shadow-key route for the four ruled cases (C half of the #11374 ruling) #11627 and commit d0e3a88 exist to end」; 「the driver-sql (MySQL): full-value UNIQUE on >768-char token columns is inexpressible on utf8mb4 — hash-shadow-key route for the four ruled cases (C half of the #11374 ruling) #11627/driver-sql (MySQL): the #11627 hash shadow drops the NULL-safe organization key part — a shadow-carried org-scoped UNIQUE reintroduces #5030's NULL-org zero-constraint #12998 suites」 became 「the driver-sql (MySQL): full-value UNIQUE on >768-char token columns is inexpressible on utf8mb4 — hash-shadow-key route for the four ruled cases (C half of the #11374 ruling) #11627 and commit df1c75c suites」; 「[driver-memory's reference matcher answers$notContainsNO for every valued NON-STRING row — the live mingo path answers YES #14079/text operator over a temporal column: SQLite matches the stored ISO text, live Postgres refuses with SQLSTATE 42883, and the JS faces answer by stored representation — no face declares the cell #15683/driver-sql: amultiple: trueBOOLEAN column loses its$containsmembership filter — the #14079 type-gate compiles it to1 = 0, where the same shape on amultiple: truenumber keeps its GLOB #17343]」 became 「[driver-memory's reference matcher answers$notContainsNO for every valued NON-STRING row — the live mingo path answers YES #14079/text operator over a temporal column: SQLite matches the stored ISO text, live Postgres refuses with SQLSTATE 42883, and the JS faces answer by stored representation — no face declares the cell #15683, commit 82cb69f]」; 「(driver-sql: the platform-objects schema does not sync onto MySQL — unbounded string fields become TEXT, which MySQL refuses to index #11374, driver-sql: explainUnkeyableTextColumn tells an upgraded deployment to declare a maxLength the field already declares — the stale-TEXT column path misdirects the operator #12999)」 became 「(commits d0e3a88 and ebcc34e)」.SqlDriverreads 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 #4311tenancy, #16570indexes) #16711 验收口径 item 4)」 became 「(验收口径 item 4 of the card commit 7862fb7 closed)」, whose message records the TS2353 negative control; 「the defect [finding] API keys carry no organization — under the isolated posture a minted key reads no org data at all (no leak, but the key surface is inert) #8287 removed and spec: audit stamping needs a read-neutral organization declaration —tenancy.tenantFieldcannot servesys_api_keywithout walling the credential table (#8707 remainder) #8778 must not reintroduce」 became 「… and commit 7901b2d's stamp-only key must not reintroduce」; 「the gap driver-sql: distinct() leaks the raw backend error with status undefined — the ADR-0112 envelope #11455 gave aggregate() never reached the third read door #17639 left FILED」 became 「the gap commit 7c2c5ae left FILED」 (9ccc4179e's message: 「the attribution arm driver-sql: distinct() leaks the raw backend error with status undefined — the ADR-0112 envelope #11455 gave aggregate() never reached the third read door #17639 deliberately left filed」); 「See the ruling recorded on [finding] driver-sql's SQLite json codec is not round-trip faithful for a string whose content is valid JSON — '123' reads back as a number, and Postgres does not agree #12380.」 became 「See the decision recorded in commit 4045b95's message.」 (that message records the posture, 「refuses to guess at the two that the pre-fix encoding made ambiguous」, and calls it no ruling).eslint.config.mjsdeclares no line-length rule, and a reflow would move neighbouring lines and every line citation into the file).Sites left
vitest.config.ts): none.describeandittitles, assertion arguments):#113745,#123804,#175904,#176394,#129983,#130153,#166093,#173433,#175863,#178573,#110672,#149022, and 12 more once each. Every one of the 24 is in this stage's population, so the table above holds an anchor for each. Non-test strings carry none. Strings are outside this stage's surface.src: the release-ownedCHANGELOG.mdnames dead numbers on 69 sites (31 numbers); left.package.json,tsconfig.json,vitest.config.ts,README.mdandLICENSEcite no dead number.Mechanical guard: no code token moves
The guard (stages 2 and 3's) compares base
222ecc27fagainst the working tree over all 55 touched files, with TypeScript 6.0.3:forEachChildwalk. Comments are trivia there, and JSDoc is never visited. A leaf that is not itself a token (an empty block) is re-scanned with trivia skipped.getChildrenwalk, JSDoc nodes skipped. String, template and numeric literals are compared in full on both readings.Results:
sql-driver.ts): 0 files changed (exit 0).hashShadowColumnFortohashShadowColumnForX,schema-drift.ts): DIFFER on both readings (exit 1).'storage'to'storageX'inFieldKeyClass,builtin-column-collision.ts): DIFFER on both readings (exit 1).MEDIA_ID_MOVE_WIDTH = 2048to2049,media-column-move.ts): DIFFER on both readings (exit 1).Each mutation went through
scripts/ablation-replace.mjs(wrap mode, anchor hit 1 to 0, replacement 0 to 1) under a shell trap that restores by absolute path fromHEAD. Each restore was proven equal to itsHEADblob (cd55a4ca44f3,72e45a83968f,86ebb324c1b6,fe0ce2c4d5bd), withgit diff HEADempty and a clean tree afterwards.Changeset:
patch(distmeasured)files[]isdist,README.mdandCHANGELOG.md, and the package is not private. The whole workspace was built first (turbo run buildover./packages/*and./packages/*/*, 71 of 71 tasks, VERDICT command-exit 0). Then the package's ownbuild(tsup pluscheck-dts-emitted) ran three times in one script under the shared verify lock (VERDICT command-exit 0):02d2a034a: 6distfiles hashed. Of the 122 rewritten non-test lines, 57 appear verbatim indist: 52 fromsql-driver.ts, 3 fromschema-drift.ts, 1 each frommedia-column-move.tsanddialect-emission-refusal.ts; inindex.d.ts/index.d.mts(51) andindex.js/index.mjs(52).index.d.ts,index.d.mts,index.js,index.mjs).HEADblob,git diff HEADempty): all 6 files are byte-identical to leg 1, so the build is deterministic and the difference is the rewrite.So the rewrite ships, and
.changeset/20595-driver-sql-provenance-anchors.mddeclares apatchfor@objectstack/driver-sql, comment text only, with the claim'sClause-②: noline.Gates (head
fad95aff7)node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsatfad95aff7(56 paths against merge base04f0cc499) derived 63 commands. All 63 ran, each exit code captured before any pipe: 63 exit 0.--ranreports 「63 derived, 63 run, 0 NOT-MEASURED, 0 UNRUN」 (a derived zero) and exits 0. The roster families the derivation flags under a touched directory also ran, each exit 0:node scripts/check-changeset-fixed.mjs,pnpm check:authz-resolver,pnpm check:error-code-casing,pnpm check:filter-alias-parity.main:mainmoved six commits after the merge, none touching a file here. A probe tree atorigin/mainf9bcd08bewith this diff applied derived 64 commands, the one addition beingnode scripts/check-dts-emitted.mjs --self-test(that script is unchanged across the range). It ran, exit 0, and--ranon the probe reports 「64 derived, 64 run, 0 NOT-MEASURED, 0 UNRUN」.node scripts/check-issue-citations.mjsexits 0 (「every citation this change adds resolves」, 10 judged across 6 files);pnpm check:issue-citationsexits 0 (self-test, 173 cases, 9 batteries);pnpm check:doc-authoringexits 0 (the sibling-package prose-id baseline holds, no growth);pnpm check:nul-bytesexits 0 (9,641 files, no raw control bytes).fad95aff7:pnpm --filter @objectstack/driver-sql test: 215 test files pass and 11 skip (226); 3,594 tests pass and 202 skip. The 11 skipped files are the live-dialect suites (PostgreSQL and MySQL cells), declared un-run locally; CI'sTemporal Conformance (live PG + MySQL)job runs them.pnpm --filter @objectstack/driver-sql typecheckexits 0;tsc --listFilesputs all 226 tracked test files and all 55 changed files in its program..tsfiles plusdist/index.jsas the control: 56 results, 0 errors and 1 warning, the control's ignore notice; none of the 55 is reported ignored.eslint.config.mjsnever enables type-aware linting (its lines 327-328 say so), so a comment edit cannot move the verdict on an untouched file. The repo-widepnpm lintis CI's run.Acceptance notes
222ecc27fand merged withmainonce, at04f0cc499, before the gates (merge02d2a034a, no conflict, no file underpackages/drivers/driver-sql, and neithercheck-issue-citations.mjsnordispatch-gates.mjs). Tests, typecheck and gates ran on the head after it. The net diff againstmainis the 55 rewritten files (+291/−291) and the changeset.sql-driver-12998-shadow-null-safe-key.test.ts:266saysinitObjects' parameter type does not declareindexes;b72226f48declared it, and the citation now reads 「(the gap commit b72226f closed)」.sql-driver.ts:18142says 「driver-sql: the platform-objects schema does not sync onto MySQL — unbounded string fields become TEXT, which MySQL refuses to index #11374's remaining half may still reshape the text side」; it was written on 2026-08-24 (c49afd0886), a day before107bb4ba4settled that half, and now reads 「the half commit d0e3a88 left open」. Comment accuracy, outside a citation sweep.sql-driver.tsas DIFFER on reading 1 alone: an emptycatch { }block has no child nodes, so its leaf text carried the comment inside it (// Pre-#12380 row: …). Reading 2 agreed with no change throughout. Reading 1 now re-scans such a leaf with trivia skipped; the real run and all four controls above are from the corrected guard.sql-driver-17639-distinct-fault-envelope.test.ts:206, listed above.Generated by Claude Code