Repository navigation
refactor(driver-sql): move introspectSchema's body out of sql-driver.ts into sql-driver-introspection.ts (#25521 cut 4) - #25698
Conversation
…ts into sql-driver-introspection.ts (#25521 cut 4) Move-only. The body of SqlDriver#introspectSchema moves unedited into cut 1's module and reaches the class through cut 1's IntrospectionHost, which gains the five members the body reads that it did not list yet (dialectName as a getter; introspectColumns, introspectForeignKeys, introspectPrimaryKeys and introspectUniqueConstraints as late-bound closures). The method keeps its name, signature and position. postgresTableNameCollisionError, read only by this body, stays in sql-driver.ts and gains a leading export. listPhysicalColumns stays in the class: its body is shorter than the host literal a stub would need. sql-driver.ts goes from 21,678 to 21,595 lines. Claude-Session: https://claude.ai/code/session_01JVTd3PprStGa26aez5omLB Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): ⛔ 3 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 28b8198efaf7b8e62e40272e9b24088568ed083d && git checkout 28b8198efaf7b8e62e40272e9b24088568ed083d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin b77bb37eb2c738c40093acb04f19fa8fc2dd605a f73c5458702810c5183e002ef92de7dd718362f2 && git checkout -B drift-repro b77bb37eb2c738c40093acb04f19fa8fc2dd605a && git merge --no-ff f73c5458702810c5183e002ef92de7dd718362f2
node scripts/docs-audit/affected-docs.mjs --json b77bb37eb2c738c40093acb04f19fa8fc2dd605a
|
席位核对ACCEPT ·
Generated by Claude Code |
Part of #25521
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Ruling-ref: 6348891160
Cut 4 of the
sql-driver.tssplit (#24586 ruling A, recorded in6270097840). The claim is6386825345. The body of the publicSqlDriver#introspectSchemamoves unedited into cut 1's module,packages/drivers/driver-sql/src/sql-driver-introspection.ts, and reaches the class through cut 1's host,IntrospectionHost. The method keeps its name, signature and position.listPhysicalColumns, the other member of the class's Schema Introspection section, stays in the class (see "Why onlyintrospectSchema").It is move-only, and the card stays open for the later cuts. Branch
claude/issue-25521-sql-driver-cut-4, cut fromorigin/mainat6021b5e83(cut 3 merged as645ede5e1before it).Net line count (the seat's rule from ACCEPT
6385306916).sql-driver.tsgoes from 21,678 lines at base to 21,595 at head: -83.sql-driver-introspection.tsgoes from 665 to 800 lines.Serial with the file's in-flight PRs. At claim the PM read no open PR touching
sql-driver.ts. Re-measured at my start (15 open PRs) and again just before this PR was opened (12 open), each PR's file list read in full. No PR touchespackages/drivers/driver-sql/**,packages/drivers/driver-turso/**orpackages/drivers/driver-sqlite-wasm/**, except the Version Packages PR #25640, which touches only those packages'CHANGELOG.mdandpackage.json(its 183 files read page by page, twice).origin/mainmoved two commits past the base meanwhile (#25603, #25684, now1fbd9de05). Neither touches the three driver packages or a gate script this diff derives, somainis not merged in.Seam table (fresh, at
6021b5e83)sql-driver.tsis 21,678 lines. 30-day lines aregit blame --line-porcelainlines whose committer time is on or after 2026-09-24T15:56:03Z, 30 days before the base commit. The clone's history floor is 2026-09-15, andscripts/pm/git-history.mjs countproves 69 commits on the file in that window. In all, 3,815 lines (17.6%) are from the last 30 days. The classSqlDriverspans lines 5499-21603 with 347 members: 251 methods (49 public), 32 statics. No public method has an inferred return type; the one inferred public member is the gettersupports, in the class head. Sections are the class's own banner comments, cut by contiguous line range. "Public" counts public methods, plus public accessors where there are any:supports)runtimeCreatedIndexesfield)releaseTransaction)introspectSchema, 15825-15928)UniqueConstraintMember,singleColumnUniqueColumnsOf the 65 Schema introspection lines from the last 30 days, 27 are
listPhysicalColumnswith its docblock and the banner (15794-15824), and 38 areintrospectSchema(15825-15928). At head the section is 52 lines (15795-15846).The limits per area are cut 1's (PR #25614), re-read on this tree:
getBuilderbuilders. Aggregation, Distinct, Window functions, Query plan analysis, CRUD and Bulk build throughgetBuilder, so a cut of any of them must first carry the new module intocheck:tenant-chokepoint'sSCAN_FILES, or rule 1 goes silently narrower. None of them is cut here.this.FIELD.delete/insert/update(.releaseTransactionhas one, and Schema sync has three. Those bodies stay.introspectSchemahas none: it calls.get(,.set(and.push(on local maps and arrays only.6385306916). An area moves only whensql-driver.ts's net line count drops.insertOnlyUpsertColumnsstays insql-driver.ts, because drivers(sql):upsert's empty-merge-set fallback is merge-ALL, which re-admits every insert-only column — currently unreachable, but it is the wrong shape for "nothing to merge" #8740's restart line names that symbol in that file. This cut does not touch it.Proposed cut 5:
introspectIndexes(Schema sync, 15097-15249, 153 lines, 0 from the last 30 days), into the samesql-driver-introspection.ts. It is protected, with an annotated return type (a promise ofPhysicalIndex[]). It reads no static and does not build throughgetBuilder, and it has nothis.FIELD.delete/insert/update(site. Its body readsknex,isMysql,isPostgresandisSqlite, whichIntrospectionHostalready lists, plusresolveHashShadowKeys, which would go as a late-bound closure. That method reads the hash-shadow statics, so it stays in the class.TursoDriveroverridesintrospectIndexesand callssuperon its local arm. Priced against the net-line rule: the stub needs one closure and four getters (13 lines) in place of a body of 96 lines, plus one name in the import, so the file drops by about 82 lines. Its docblock cites ADR-0048 and stays on the class, so the anchored decision-letter count should not move. The next candidate after it is the SQLite rebuild pairapplyDriftOpInPlaceandrebuildSqliteTablePatched(14858-15048, 0 from 30 days; 6 and 10 host members). Every other cold area left builds throughgetBuilder.Why
introspectSchema, and why cut 1's moduleintrospectSchemamoves. It is public, its return type is annotated (a promise ofIntrospectedSchema), it reads no static and nogetBuilder, and it has nothis.FIELD.delete/insert/update(site. Its 104 lines include 38 from the last 30 days.introspectSchemais the public whole-schema read that cut 1's five catalog helpers serve, and that module's header already says so. Its body calls four of those helpers. Four of the five fields and getters it reads (knex,isMysql,isPostgres,isSqlite) are alreadyIntrospectionHostmembers. A new module would declare a second host typing the same four members, and card ask 2 asks for one named host per shared surface, not a second copy. One name joins the existing import line insql-driver.ts. A new module would add an import block and its comment, which counts against the net-line rule.Why only
introspectSchemaThe seat's ACCEPT on cut 3 keeps a body in the class when it is shorter than its host literal.
listPhysicalColumnsis that case. Its body is 6 lines, and it readsknex,physicalTableByObjectandphysicalSchemaByObject. A stub would need three getters: 10 lines in place of 6, plus one more name in the import. Sosql-driver.tswould grow by 5 lines. Moving it withintrospectSchemawould still leave the area net-negative (-78 instead of -83). But that member alone would make the file longer, so it stays. This is open question 1 in the report.Overrides and spies, measured before the move
TursoDriveroverridesintrospectSchema(its'refused'door row) and callssuper.introspectSchema()on its local arm. The class method is still there and hands the body its host.TursoDriveralso overridesintrospectColumns(one parameter, callssuper). The moved body reachesintrospectColumnsthrough a late-bound closure, so that override is still the one it calls.TursoDriver's door table listsdialectNameas'inherited'.SqliteWasmDriveroverrides the getterisSqlite. The host reads it through a getter that reads the driver, so the override is the one the body sees.sql-driver-12732-varchar-emitter-parity-wiring.test.tsspies onintrospectColumnson the instance, and the closure reaches that spy.service-datasourcetests spy onintrospectSchemaitself, which is still the class method.distgave 14 readings, identical at base and at head. It covered the plain SQLite answer (tables, columns, keys, foreign keys,dialect,introspectedAt), instance spies on all four helpers (2 calls each), a spy onintrospectColumnsthat answers its own columns, a subclass override ofintrospectColumnswith one parameter, a subclass override of thedialectNamegetter, a subclassintrospectSchemathat callssuper, and a helper that rejects, which rejects the whole read. The probe is not committed.The shape (#23050 shape B, as cuts 1-3 apply it)
introspectSchemawith its name, signature and position. Its body is now one host literal plusintrospectSchema.call(host), marked[#25521 cut 4]. It dropsasyncand returns the moved function's promise. The method has no docblock, at base or at head.IntrospectionHostgains five members, each typed as the class member (an indexed access onSqlDriver):dialectName(read-only, a getter) andintrospectColumns,introspectForeignKeys,introspectPrimaryKeysandintrospectUniqueConstraints(late-bound closures). Cut 1's five member lines are unchanged. The moved function types itsthisas thePickof the host over exactly the nine members its body reads. The generator measures those reads from the AST and asserts them, and the stub annotates its literal as theThisParameterTypeof the moved function. There is no cast, and no member becomes public.IntrospectedSchemaandIntrospectedTable, whichsql-driver.tsalready exports, andpostgresTableNameCollisionError, which only this body reads. That function stays insql-driver.tsand gains a leadingexport. This is cut 2's shape, accepted there as option A: it moves only method bodies and keeps every path citation true. The value import is read only inside the function body, so the module cycle is evaluation-safe, as in cut 1.index.tsre-exports nothing new.sql-driver.tsis re-worded to nameintrospectSchema. Both are comment-only.The published
.d.tsdoes not changeUnder the series bar (ruling
6348891160, letter A), measured on base6021b5e83and on headf73c54587. Both were built against the same dependency tree. At base:turbo run build --filter=@objectstack/driver-turso... --filter=@objectstack/driver-sqlite-wasm..., 9/9 tasks, 0 cached, with the basesql-driver.tsand module restored into the worktree after the cut commit. At head:pnpm --filter @objectstack/driver-sql build.dist/index.d.tsanddist/index.d.mts(there is no.d.cts). The two are identical to each other at both ends.93da45168e82136b7613944525e47402d5dc6f9f8daa9efa4bdceeaa11b52a89(cuts 1-3's hash, unchanged). The raw diff is 0 lines.93da45168e82136b7613944525e47402d5dc6f9f8daa9efa4bdceeaa11b52a89. The file has 0 double-quoted unions, so that normaliser rewrites nothing.118e992ad8aad590044eb31509dca65e6b321e3410ce846e1e5f5dd34b956e95. The raw diff is 0 lines, so the proof rests on raw identity and neither normaliser is relied on.dist/index.d.ts, in the same block: line 5899,introspectSchema(): Promise...;, madeprotected. That gives raw and double-quote-normalised402f862acf50c10714bd3aef080c5b397a15b9ef1712180ee86cf30a25e6709c, and single-quote-normalisede12430bcae9b43a1e4e9ff7914e5c12a534cc1765bc3c32a642a11977e4812ae. Each differs from the real hash.import()andrequireof the built bundles). The sorted list hashes tod61a9dd3a02661602b1bb2dbe18152ac43986148f36b2746f40c0884bd8ffdecon all four.dist/index.mjsanddist/index.jseach contain 15 host.call(sites (14 at base, plus this one).No changeset:
skip-changeset, per ruling6348891160item 4.Proof of move-only
getChildrenleaves). The moved function's parameters (less the addedthis), return type and body have the same token sequence as the base method, andasyncmatches. 567 tokens compared, 0 differ.thisparameter is removed.'sqlite_%'becomes'sqlite%'inside the SQLite arm's template literal. The check then reports 1 token and 1 line different, and it exitsPROOF FAILED, exit 1.async.sql-driver.ts: 202 non-class statements at base and head. 200 are byte-identical, in order.postgresTableNameCollisionErroris identical except for a leadingexport. The import from./sql-driver-introspection.jsgains exactly one specifier,introspectSchema, and its leading comment is re-worded.IntrospectionHostkeeps all five of its member lines and gains the five above. The imports gain the type importsIntrospectedSchemaandIntrospectedTableand the value importpostgresTableNameCollisionError, and lose nothing. The module has no other statement.Readers of
sql-driver.tsby path, checked against the moved textNone needed an edit. Each was read against the moved region (15825-15928) 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 the moved body, so per card ask 3 no entry is owed. The moved body cites no ADR, and only issue numbers.listPhysicalColumns's docblock cites ADR-0131 D7, and it stays.check:adr-anchors: 85 anchored files at base and head. Decision-letter citations on the anchored surface: 1,847 at base and 1,847 at head.docs/qa/platform-checklist/areas/integration-system.jsonnamessql-driver.ts#introspectSchemaas a source of one item. The method declaration is still insql-driver.ts, so the anchor resolves. Its parenthetical, "SQLite branch reads sqlite_master", now describes a body one module over (see the acceptance notes).check:adr-symbol-anchors: 2,384 anchors resolve at both ends.check:tenant-chokepoint. Rule 1 readsgetBuilderbindings, and the moved text has none: 24 bindings across 3 files at both ends. Rule 2 visits everyraw-family call inSCAN_FILESwhose text saysIS NULLagainst a tenant column. The moved body holds three such calls, all catalog listings (information_schema.tables,sqlite_master). None saysIS NULLor names a tenant column. So rule 2's verdict is unchanged, but its inspected population insql-driver.tsdrops from 76 literal raw fragments to 73 (see the acceptance notes).check:logger-receiver-detach: 0 detaches at both ends.logger-receiver-detach.test.ts③,sql-driver-compile-refusal-seam.test.ts(noINVALID_FILTERbuilder;postgresTableNameCollisionErrorbuilds aRESOURCE_CONFLICTerror and did not move), the fivepackages/cligenerate-*.pin.test.tsfiles,check-keyed-text-bounds,check-object-def-param-keys.turbo.json,scripts/cross-package-test-inputs.mjs,scripts/pm/check-half-states.mjs,scripts/check-changeset-no-major.mjs,packages/spec/liveness/*.jsonevidence). None reads the moved body. ADR-0015 listssql-driver.ts (introspectSchema, …)among its files. That is still true of the method, and nodocs/adr/**edit is made here.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-configoverpackages/drivers/driver-sql/src(265 files, the new module included): 0 errors, 0 warnings.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, against the rebuiltdistat each end: base 2,526 tests (2,492 passed, 0 failed, 34 skipped; 95 files), head the same. Per test name and status there is no difference (2,513 distinct names; 13 names repeat).packages/drivers/driver-sqlite-wasmsuite, against the rebuiltdist: base 704 tests (704 passed; 39 files), head the same, with no difference per test name.dispatch-gates --commandson this diff, at headf73c54587: 55 derived commands, each run 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), which CI runs.check:lean-entry-closureran afterobjectqlwas built.Acceptance notes
check:tenant-chokepointrule 2 reads 3 fewer raw fragments.SCAN_FILESnamessql-driver.tsand not the seam modules, so rule 2 (noIS NULLarm on a tenant column) no longer visits the three catalog-listingknex.raw(calls that moved. None of the three is an arm on a tenant column today. A future edit that added one in the module would not be caught by rule 2. Cut 1 already moved 16 catalog raw fragments into this module the same way. WideningSCAN_FILESis a gate edit, and it is the open precondition the series carries for thegetBuilderareas. It is not made here.integration-system.json, "sql-driver.ts#introspectSchema(introspectSchema; SQLite branch reads sqlite_master …)") still resolves to the method, which still answers the same way. The SQLite branch it describes now lives insql-driver-introspection.ts. The file is outside this claim's file surface, and a checklist item edit takes a history revision. So it is left as is and raised in the report as open question 2.TursoDriver'sintrospectSchemaoverride still callssuper.introspectSchema(). That now returns the moved function's promise instead of anasyncmethod's promise. A caller awaits the same settlement.Generated by Claude Code