Repository navigation
refactor(driver-sql): move the raw-execution path out of sql-driver.ts into sql-driver-raw-execution.ts (#25521 cut 2) - #25630
Conversation
…s into sql-driver-raw-execution.ts (#25521 cut 2) Move-only. The bodies of SqlDriver#execute, #rawStatementFault and #noteRuntimeIndexDdl move unedited into a new module and reach the class through one named host (RawExecutionHost): knex, logger and runtimeCreatedIndexes as getters, rawStatementFault and noteRuntimeIndexDdl as late-bound closures so subclass overrides and spies still dispatch. The class keeps each method's name, signature, docblock and position. The seven module-level declarations the bodies read stay in sql-driver.ts and gain an `export` so the new module can import them; index.ts re-exports nothing new. Claude-Session: https://claude.ai/code/session_01RvoeGVyNRC3zkVrNsLbm8M Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check14 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. 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 9b394818531587e01f18beed385a0337c52c4ce9 && git checkout 9b394818531587e01f18beed385a0337c52c4ce9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin cc10e74fefc6ca104b0d9159b23783b94499a119 a92731ec28863774f1f5ba42d269f6c136c9952a && git checkout -B drift-repro cc10e74fefc6ca104b0d9159b23783b94499a119 && git merge --no-ff a92731ec28863774f1f5ba42d269f6c136c9952a
node scripts/docs-audit/affected-docs.mjs --json cc10e74fefc6ca104b0d9159b23783b94499a119 |
席位核对ACCEPT · Checklist conclusions (read on GitHub, not from the report):
Deviations accepted: as reported (trailers in the AGENTS.md form; the platform-created branch; deepened history; main not merged in, since the 3 new main commits touch none of the three drivers or a derived gate; the merge queue builds on current main). Carried to cut 3: the dev proposes Transactions less Landing: Generated by Claude Code |
Part of #25521
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Ruling-ref: 6348891160
Cut 2 of the
sql-driver.tssplit (#24586 ruling A, recorded in6270097840). The claim is6383192755. ThreeSqlDrivermethod bodies move unedited into a new module,packages/drivers/driver-sql/src/sql-driver-raw-execution.ts: the publicexecute, its protected refusal terminalrawStatementFault, and the protectednoteRuntimeIndexDdl, which records the index DDLexecuteran.It is move-only, and the card stays open for the later cuts. Branch
claude/issue-25521-sql-driver-cut-2, cut fromorigin/mainatf7b029896(cut 1's merge).Serial with the file's in-flight PRs. At claim the PM read no open PR touching
sql-driver.tsordriver-turso/src. Re-measured after my first push (14 open PRs, each PR's file list read in full from its head, merge base to head) and again just before this PR was opened (13 open; #25617 had merged). None touchespackages/drivers/driver-sql/src/**orpackages/drivers/driver-turso/src/**.origin/mainmoved three commits past the base meanwhile (#25612, #25615, #25617, nowcc10e74fe). None of them touchesdriver-sql,driver-turso,driver-sqlite-wasmor a gate script this diff derives, somainis not merged in.Seam table (fresh, at
f7b029896)sql-driver.tsis 21,675 lines. 30-day lines aregit blame --line-porcelainlines whose committer time is on or after 2026-09-24T10:03:29Z, 30 days before the base commit. History was deepened to 2026-09-15 first, andscripts/pm/git-history.mjs countproves 68 commits on the file in that window (19 in the last 7 days). In all, 3,855 lines (17.8%) are from the last 30 days. The classSqlDriverspans lines 5482-21600 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)listPhysicalColumns,introspectSchema)UniqueConstraintMember,singleColumnUniqueColumnsThe 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 the gate goes silently narrower. None of them is cut here.this.FIELD.delete/insert/update(. Transactions has one,releaseTransaction(this.openTransactions.delete(key)), and Schema sync has three. Those bodies stay. Raw execution has none:noteRuntimeIndexDdlcalls.delete(on a localSet, and calls.get(,.set(and.values()on the ledger.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 3: Transactions less
releaseTransaction(10923-11000, 78 lines, 0 from the last 30 days). That isbeginTransaction,assertBareKnexSafe,commit,rollback,commitTransactionandrollbackTransaction. Every return type is annotated, and none readsgetBuilderor a static.releaseTransactionstays, for itsthis.openTransactions.delete(site. The bodies call it through a late-bound closure, asexecutecallsrawStatementFaulthere. Schema introspection (136 lines, 65 from 30 days) is the next candidate after that.Why this area for cut 2
Cut 1 proposed it, and it re-measures clean: 126 lines, 12 from the last 30 days. Its one public member,
execute, has an annotated return type (aPromiseofunknown, pinned bysql-driver-doors-declared-types.test.ts). It has no static and nogetBuilder, and nothis.FIELD.delete/insert/update(site. Between them, the three bodies read onlyknex,logger,runtimeCreatedIndexesand each other (executecallsrawStatementFaultandnoteRuntimeIndexDdl). The fieldruntimeCreatedIndexesand its docblock stay on the class: schema sync also reads the ledger (the index-drift diff in the Schema sync section). Both subclasses reach the moved bodies.TursoDriveroverridesexecute, callssuper.execute, and callsrawStatementFaultat eight sites.SqliteWasmDriverinherits all three.The shape (#23050 shape B, as cut 1 applies it)
.d.ts. Each body is now one host literal plusfn.call(host, ...), marked[#25521 cut 2].executedropsasyncand returns the moved function's promise. The other two were neverasync.RawExecutionHostis 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. The generator lists them, and they were checked against thethis.reads of each base body. Each stub annotates its literal as theThisParameterTypeof the moved function. There is no cast, and no member becomes public.knex,loggerandruntimeCreatedIndexesgo as getters, so each read happens when the body makes it.rawStatementFaultandnoteRuntimeIndexDdlgo as late-bound closures. So a subclass override is still the oneexecutereaches:sql-driver-21385-refusal-log-line-redaction.test.tsandturso-driver-16019-remote-raw-statement-fault-envelope.test.tsoverriderawStatementFaultand callsuper. A spy on the instance is reached the same way.this.logger.warn(...)keeps its receiver: the getter hands back the class's logger, and.warnis called on it.sql-driver.ts:OWN_STATEMENT_FAULT,INDEX_DDL_PREFIX,CREATE_INDEX_DDL,DROP_INDEX_DDL,unquoteSqlIdentifier,lastIdentifierSegmentandrawStatementFaultError. All seven stay where they are, each gains a leadingexport, and the new module imports them back. They stay becauseOWN_STATEMENT_FAULThas readers that did not move (four other refusal lines). They also stay because tests in four other packages (types,cli,metadata,metadata-protocol) citerawStatementFaultError"verbatim (sql-driver.ts)" by path. Every value import is read only inside a function body, so the module cycle is evaluation-safe, as in cut 1.index.tsre-exports nothing new, so the published surface does not move (proof below). This is the one place the cut differs from cut 1's shape: cut 1 needed no newexport. It is recorded as an open question in the report.The published
.d.tsdoes not changeUnder the series bar (ruling
6348891160, letter A), measured on basef7b029896and on heada92731ec. Both were built against the same dependency tree:turbo run build --filter=@objectstack/driver-turso... --filter=@objectstack/driver-sqlite-wasm...at base, 9/9 tasks, 0 cached (remote caching disabled). 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(cut 1's head hash, unchanged). The raw diff is 0 lines.93da45168e82136b7613944525e47402d5dc6f9f8daa9efa4bdceeaa11b52a89. This file has 0 double-quoted unions, so that normaliser rewrites nothing.118e992ad8aad590044eb31509dca65e6b321e3410ce846e1e5f5dd34b956e95. With a raw diff of 0 lines, the proof rests on raw identity. The single-quote pass is reported only because the dispatch asked for it.dist/index.d.ts: line 4217,protected rawStatementFault(command: string, error: unknown): Error;, made public. That gives raw and double-quote-normalised47c79477965c2473c4a079afd8c4c8f47bc9f36213ac7dcfa2df99be7f081688and single-quote-normalised464658c31cd8f7ee5c779054428fe3f8d3c520610061252de5567e05a480ccd2, each different from the real hash.import()andrequireof the built bundles). The sorted list hashes tod61a9dd3a02661602b1bb2dbe18152ac43986148f36b2746f40c0884bd8ffdecon all four.dist/index.mjsanddist/index.jseach contain 8 host.call(sites (cut 1's 5 plus these 3).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, andasyncmatches on all three. 404 tokens compared, 0 differ.rawStatementFaultin a copy of the module makes the check report 1 token and 1 line different, and it exitsPROOF FAILED.asynconexecute.sql-driver.ts: 200 base statements other than the class. 193 are byte-identical. 7 are byte-identical except for a leadingexport. They stay in order. The one new statement is the import of the new module.sql-driver.tsgoes from 21,675 to 21,651 lines, andsql-driver-raw-execution.tshas 133.Readers of
sql-driver.tsby path, checked against the moved textNone needed an edit. Each was read against the moved region (10797-10922) 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 bodies cite no ADR at all. The docblocks that cite ADR-0048 and ADR-0112 stay on the class.check:adr-anchors: 85 anchored files at base and head. Decision-letter citations on the anchored surface: 1,871 at base and 1,871 at head.execute,rawStatementFault,noteRuntimeIndexDdlor the seven module-level declarations insql-driver.ts, and the stubs keep every member name anyway.check:adr-symbol-anchors: 2,384 anchors resolve at both ends.check:tenant-chokepointreadssql-driver.tsforgetBuilderbindings and forIS NULLarms in raw fragments. The moved text has nogetBuilder. Its one raw call,this.knex.raw(command, ...), passes a variable, which that gate does not read (its header names this case as outside its view). So the gate saw nothing in the moved text, and it still covers the same population: 24getBuilder()bindings across 3 files at both ends.logger-receiver-detach.test.ts③ scanssql-driver.tsfor detach-then-call shapes. The movedthis.logger.warn(is a direct call, not a finding. The repo-widecheck:logger-receiver-detachwalks everypackages/**source, so it covers the new module: 0 detaches at head.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-object-def-param-keys(no(obj as any).KEYread).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 other unmoved symbols.rawStatementFaultError… (sql-driver.ts)") stay true, because that function did not move.driver-tursoanddriver-sqlite-wasm: their readers of moved members reach the stubs unchanged. Both suites ran 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.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 there is no difference (2,513 distinct names; 13 names repeat).packages/drivers/driver-sqlite-wasmsuite, against the rebuilt headdist: base 704 tests (704 passed; 39 files), head the same, per test name no difference.dispatch-gates --commandson this diff, at heada92731ec: 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. Two gates first answered exit 3 for prerequisites and then exit 0:check-plugin-teardown-shape --self-testafter its pinned fixture commit621a4876was fetched, andcheck:lean-entry-closureafterobjectqlwas built.Acceptance notes
sql-driver.tsgainexport, so the moved bodies can import them without a second copy. The package's public surface does not change (raw.d.tsidentity, export tables). Moving the five declarations only the moved bodies read into the new module was the alternative. It was not taken: other packages citerawStatementFaultErrorinsql-driver.tsby path, andOWN_STATEMENT_FAULTwould need the export anyway.TursoDriver'sexecuteoverride still callssuper.execute, which now returns the moved function's promise instead of anasyncmethod's promise. A caller awaits the same settlement.Generated by Claude Code