Repository navigation
refactor(driver-sql): move the catalog-introspection helpers out of sql-driver.ts into sql-driver-introspection.ts (#25521 cut 1) - #25614
Conversation
…ql-driver.ts into sql-driver-introspection.ts Move-only: the bodies of introspectColumnOrder, introspectColumns, introspectForeignKeys, introspectPrimaryKeys and introspectUniqueConstraints move unedited into a new module. The class keeps each method with its name, docblock and signature (less `async`); each body is now one host literal of exactly the IntrospectionHost members it reads plus `fn.call(host, ...)`. knex and the three dialect getters go as getters; introspectColumns reaches introspectColumnOrder through a late-bound closure, so TursoDriver's override and test spies keep working. Claude-Session: https://claude.ai/code/session_01JVTd3PprStGa26aez5omLB Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): ⛔ 1 release-owned page(s) name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 13 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 9464a3b2c055098a1d391bf6071bc0f4399a54a9 && git checkout 9464a3b2c055098a1d391bf6071bc0f4399a54a9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e649c2d91e270e3da26820bcfe54a28445305a75 021043d5785a5a7d0f0978a3302b2e4f84037e91 && git checkout -B drift-repro e649c2d91e270e3da26820bcfe54a28445305a75 && git merge --no-ff 021043d5785a5a7d0f0978a3302b2e4f84037e91
node scripts/docs-audit/affected-docs.mjs --json e649c2d91e270e3da26820bcfe54a28445305a75
|
席位核对ACCEPT · Checklist conclusions (read on GitHub, not from the report):
Deviations accepted: 1 (commit trailers in the AGENTS.md form), 2, 3, 4 (no anchor entry owed: no anchored paragraph describes a moved body), 5–8 as reported. Carried to the next slice of #25521 (not filed): a cut in a Landing: Generated by Claude Code |
Part of #25521
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Ruling-ref: 6348891160
Cut 1 of the
sql-driver.tssplit (#24586 ruling A, recorded in6270097840), with the fresh seam table the card asks for first. The claim is6382121925. FiveSqlDrivermethod bodies move unedited into a new module,packages/drivers/driver-sql/src/sql-driver-introspection.ts: the protected catalog-introspection helpersintrospectColumnOrder,introspectColumns,introspectForeignKeys,introspectPrimaryKeysandintrospectUniqueConstraints.It is move-only, and the card stays open for the later cuts. Branch
claude/issue-25521-sql-driver-cut-1, cut fromorigin/mainate649c2d91.Serial with the file's in-flight PRs. At claim the PM read 13 open PRs, none touching the file. Re-measured at my start (12 open PRs) and again just before this PR was opened (13 open PRs), each PR's file list read in full: none touches
packages/drivers/driver-sql/src/sql-driver.tsorpackages/drivers/driver-turso/src/turso-driver.ts.origin/maindid not move between the base and this PR.Seam table (fresh, at
e649c2d91)sql-driver.tsis 22,158 lines. 30-day lines aregit blame --line-porcelainlines whose committer time is on or after 2026-09-24T08:02Z, 30 days before the base commit; history was deepened to 2026-09-15 first, andscripts/pm/git-history.mjs countproves 67 commits on the file in that window. In all, 3,790 lines (17.1%) are from the last 30 days. The classSqlDriverspans lines 5471-22083 with 347 members: 251 methods (49 public, 202 private or protected), 32 statics. One public member has an inferred return type (supports, in the class head). Sections are the class's own banner comments, cut by contiguous line range:supports)listPhysicalColumns,introspectSchema)formatInput/formatOutputUniqueConstraintMember,singleColumnUniqueColumnsLimits measured per area, for pricing the next cuts:
check:tenant-chokepointscansSqlDrivermethods forthis.getBuilder(read builders. Aggregation, Distinct, Window functions, Query plan analysis, CRUD and Bulk build throughgetBuilder, so a cut of any of them must also carry the new module into that gate'sSCAN_FILES(and teach it module-level functions with athisparameter), or the gate would go silently narrower. That is a gate edit; it was kept out of cut 1.SqlDriver.hashShadowColumnForandSqlDriver.MAX_KEYABLE_VARCHAR_CHARS; the row-size explainers (19682-19977) read four protected statics. A module function cannot read a protected static, so those bodies stay unless a ruling says otherwise.this.FIELD.delete/insert/update(. One site in the whole class:releaseTransaction(this.activeTransactions.delete(, aMap), in Transactions; three in Schema sync.driver-sqlis outside the tenant-audit census corpus (SURFACE_ROOTSispackages/servicesandpackages/plugins), so theUNTYPED_RECEIVERSlimit does not bite here; cut 1 has no such site either way.Proposed cut 2: Raw execution (10786-10911, 126 lines, 12 from the last 30 days).
rawStatementFault,execute(public, annotatedunknown-promise return) andnoteRuntimeIndexDdl. They read nogetBuilderand no static; the fieldruntimeCreatedIndexesstays on the class.TursoDriveroverridesexecuteand callsrawStatementFault, which the stub shape keeps working. The bigger cold areas (Distinct, Aggregation, Query plan analysis) need thecheck:tenant-chokepointquestion answered first.Why this area for cut 1
The five helpers form a closed cluster at the tail of the class: 693 lines of methods, 19 from the last 30 days, no public member, every return type annotated, no static, no
this.FIELD.delete/insert/update(site, nogetBuilder. Between them they read onlyknex,isPostgres,isMysql,isSqliteand each other (introspectColumnscallsintrospectColumnOrder). Because the cluster ends the class, no line above 21386 moves, so no line reference into the file above that point shifts. They are also among the file's best-covered members: 17 test files in this package name them, most reaching the protected methods through a test subclass, anddriver-tursooverridesintrospectColumnsand callssuper.The shape (#23050 shape B, as #25467 cut 1 / PR #25494 applies it)
.d.ts. Each body is now one host literal plusfn.call(host, ...), marked[#25521 cut 1]. The methods dropasyncand return the moved function's promise.IntrospectionHostis new. It types every member as the class member itself (an indexed access onSqlDriver). Each moved function types itsthisas thePickof the host over exactly the members its body reads (measured from the body, and asserted by the generator), and each stub annotates its literal as theThisParameterTypeof the moved function. No cast, and no member becomes public.knex(a field) and the three dialect getters go as getters, so each read happens when the body makes it.introspectColumnOrdergoes as a late-bound closure, so a subclass override or a spy on the instance is still the oneintrospectColumnsreaches.this.knex(tableName)now calls knex with the host as its receiver; knex's callable reads its own closure (createQueryBuilder(knex.context, ...)inmake-knex.js), never its receiver.UniqueConstraintMember,singleColumnUniqueColumns,IntrospectedColumnandIntrospectedForeignKey. All four stay insql-driver.ts, which already exports them (a test importssingleColumnUniqueColumnsfrom there), and the module imports them back. The one value import is read only inside a function body, so the module cycle is evaluation-safe. Noexportwas added anywhere.The published
.d.tsdoes not changeUnder the series bar (ruling
6348891160, item 1), measured on basee649c2d91and on head021043d57, both built against the same dependency tree (turbo run build --filter=@objectstack/driver-turso...at base, 8/8 tasks, 0 cached; thenpnpm --filter @objectstack/driver-sql buildat head).dist/index.d.tsanddist/index.d.mts(there is no.d.cts); the two are identical to each other at both ends.93da45168e82136b7613944525e47402d5dc6f9f8daa9efa4bdceeaa11b52a89. The raw diff is 0 lines.93da45168e82136b7613944525e47402d5dc6f9f8daa9efa4bdceeaa11b52a89. The normaliser is the ruling's, verbatim, run frompackages/drivers/driver-sql:.d.tsspells its string-literal unions with single quotes (31 such unions, 0 double-quoted), so the normaliser rewrites nothing here and normalised equals raw. The proof therefore rests on the raw identity, which is stronger.dist/index.d.ts: line 8165,protected introspectColumns(...), made public gives raw and normalisede85d733d6d77d1a644666cc45167bf25bd4f1e13bef0a80af977a469339b5823, different from the real hash.import()andrequireof the built bundles). The sorted list hashesd61a9dd3a02661602b1bb2dbe18152ac43986148f36b2746f40c0884bd8ffdecon all four.dist/index.mjsanddist/index.jseach contain the 5 host.call(sites.No changeset:
skip-changeset, per ruling6348891160item 4.Proof of move-only
getChildrenleaves): each moved function's parameters (less the addedthis), return type and body have the same token sequence as the base method;asyncmatches on all five. 1,546 tokens compared, 0 differ. The only tokens whose text moved are the three parameter-level JSDoc comments ononFailure, equal after removing exactly two columns per continuation line.introspectColumnOrdermakes the check report a difference, at token and at line level.async.sql-driver.ts: all 199 base statements other than the class are byte-identical, in order. The one new statement is the import of the new module.sql-driver.tsgoes from 22,158 to 21,675 lines (each stub keeps its docblock and carries its host literal);sql-driver-introspection.tshas 665.Readers of
sql-driver.tsby path, checked against the moved textNone needed an edit; each was read against the moved region (lines 21386-22083) and run at both ends where it is a gate or test:
scripts/adr-anchors/packages__drivers__driver-sql__src__sql-driver.ts.jsoncarries ADR-0053 (formatOutput,presentReadValue) and ADR-0120 D4; neither paragraph describes a moved body, so per card ask 3 the new module gets no entry of its own. The moved text cites only a bareADR-0015(no decision letter), which is not in the entry.check:adr-anchors: 84 anchored files at base and head; decision-letter citations on the anchored surface 1,883 at base and 1,883 at head.sql-driver.ts#introspectSchema(unmoved); no anchor names a moved member, and the stubs keep every name anyway.check:adr-symbol-anchors: 2,384 anchors resolve at both ends.logger-receiver-detach.test.ts(the moved text has nologgerread),sql-driver-compile-refusal-seam.test.ts(noINVALID_FILTERbuilder), the fivepackages/cligenerate-*.pin.test.tsfiles (createColumnand the varchar constants),check-keyed-text-bounds(varcharColumnChars),check-tenant-chokepoint(24getBuilder()bindings across 3 files at both ends; none in the moved text),check-object-def-param-keys(TursoDriver's override ofintrospectColumnsstill matches the stub's signature).turbo.json,scripts/cross-package-test-inputs.mjs,scripts/pm/check-half-states.mjs,scripts/check-changeset-no-major.mjs,packages/spec/liveness/*.jsonevidence): the readers they serve readcreateColumn, the varchar constants or unmoved symbols.driver-turso: its only reader of a moved member isintrospectColumns, an override that callssuper.introspectColumns; it reaches the stub and is unchanged. Its suite was run at both ends (below).check:driver-conformanceat base and head: 55 covered, 0 in the DEBT ledger, 0 exempt, both times.Verification
tsc --noEmit(driver-sql) exit 0;eslint --no-inline-configon both source files exit 0 (base file also exit 0).packages/drivers/driver-sqlsuite: base 3,999 tests (3,787 passed, 0 failed, 212 skipped; 247 files); head the same. Compared per test name and status from vitest's JSON reporter: no test lost, none changed status, none added.packages/drivers/driver-tursosuite (run against the rebuilt headdist): base 2,526 tests (2,492 passed, 0 failed, 34 skipped; 95 files); head the same, per test name and status no difference.dispatch-gates --commandson this diff: 55 derived commands, each run at head with its exit code;--ranreconciles 55 derived, 54 run, 1 NOT MEASURED, 0 unrun. The NOT MEASURED one ischeck:dual-build-cjs-loads(exit 3, PREREQUISITE NOT MET: it needs every package'sdist); CI runs it.check-plugin-teardown-shape --self-testandcheck:lean-entry-closurefirst answered exit 3 for prerequisites (a pinned fixture commit outside the shallow clone;objectql'sdist), and exit 0 after fetching that commit and buildingobjectql.Acceptance notes
6348891160item 4 says no changeset andskip-changesetfor a cut that meets item 1, and the dispatch says the same. This PR follows the ruling.adr-anchorsentry per new module) is the reference PR's shape, not a rule; card ask 3 makes the entry conditional on a paragraph describing a moved body, and none does here.Generated by Claude Code