Repository navigation
refactor(driver-sql): move introspectIndexes's body out of sql-driver.ts into sql-driver-introspection.ts (#25521 cut 5) - #25931
Conversation
…ction.ts Move-only: the body of SqlDriver#introspectIndexes moves unedited into the module the other catalog reads live in, and the class method hands it its host (the dialect getters and knex as getters, resolveHashShadowKeys as a late-bound closure so a subclass override or an instance spy still dispatches). The method keeps its docblock and signature, less async, so the published declarations do not move. sql-driver.ts no longer reads parseIndexDdl or applyIndexKeyParts and drops them from its import; the module imports them from schema-drift.ts. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013Wyp3j7s8XDQmCUaKPbmXH
📓 Docs Drift Check6 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 69538bdc6117007d80dbff73def3d32775d9badb && git checkout 69538bdc6117007d80dbff73def3d32775d9badb
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2a728ba2acf52c13d1918c2afca7b79bf391e1f5 bd1670fe011f23dd40219d0d59b1a65e6e2f4991 && git checkout -B drift-repro 2a728ba2acf52c13d1918c2afca7b79bf391e1f5 && git merge --no-ff bd1670fe011f23dd40219d0d59b1a65e6e2f4991
node scripts/docs-audit/affected-docs.mjs --json 2a728ba2acf52c13d1918c2afca7b79bf391e1f5 |
席位核对ACCEPT ·
Generated by Claude Code |
Requested by Elon · project thread
Part of #25521
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Ruling-ref: 6348891160
Cut 5 of the
sql-driver.tssplit (#24586 ruling A, recorded in6270097840). The claim is6408067063. The body of the protectedSqlDriver#introspectIndexesmoves 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, which gains one member. The method keeps its name, docblock, signature (lessasync) and position.resolveHashShadowKeys, the one class method the body calls, stays in the class with the rest of the hash-shadow family.It is move-only, and the card stays open for the later cuts. Branch
claude/project-thread-8aooxu(platform-assigned to this card thread, as the claim records), cut fromorigin/mainatf00e8d5c8(cut 4 merged asb1790841bbefore it).Net line count (the seat's rule from ACCEPT
6385306916).sql-driver.tsgoes from 21,595 lines at base to 21,512 at head: -83 (cut 4 priced it at about -82).sql-driver-introspection.tsgoes from 800 to 927 lines.Serial with the file's in-flight PRs. At claim the seat read no open PR touching
sql-driver.ts(hot-file queue on seat post #20966: this is the one slice in flight). Re-measured just before this PR was opened: 8 open PRs, each file list read in full. None touchespackages/drivers/driver-sql/**,driver-turso/**ordriver-sqlite-wasm/**, except the Version Packages PR #25640, which touches only those packages'CHANGELOG.mdandpackage.json.origin/mainmoved one commit past the base meanwhile (#25904, now2a728ba2a). It touches no driver package and no gate script this diff derives, and it merges clean, somainis not merged in.The area, re-measured at
f00e8d5c8introspectIndexeswith its docblock is lines 15096-15250 ofsql-driver.ts(155 lines; the method itself 15143-15250).git blamewith--since30 days before the base attributes 0 of those lines to the last 30 days; the file has 63 commits in that window (the clone's history was deepened to 2026-09-20, before the window opens, for the reading).PhysicalIndex[]), so the inferred-return limit does not bite.getBuilder(check:tenant-chokepointrule 1: 24 bindings across 3 files at both ends).knex,isMysql,isPostgresandisSqlite, all alreadyIntrospectionHostmembers, plus the methodresolveHashShadowKeys.this.FIELD.delete/insert/update(site: its.set(/.get(/.push(calls are on a localMapand local arrays.insertOnlyUpsertColumnsis not touched (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).The shape (#23050 shape B, as cuts 1-4 apply it)
introspectIndexes, docblock and parameter JSDoc included, byte-identical except thatasyncis dropped. Its body is now one host literal plusintrospectIndexes.call(host, tableName, opts), marked[#25521 cut 5]. It returns the moved function's own promise, so a caller awaits the same settlement.IntrospectionHostgains one member,resolveHashShadowKeys, typed as the class member (an indexed access onSqlDriver). Its ten existing member lines are unchanged. The moved function types itsthisas thePickof the host over exactly the five members its body reads, and the stub annotates its literal as theThisParameterTypeof the moved function. There is no cast, and no member becomes public.knexand the three dialect getters go as GETTERS that read the driver at call time.resolveHashShadowKeysgoes as a late-bound closure that calls it on the driver, so a subclass override or an instance spy is still the one the body reaches.resolveHashShadowKeysstays. The claim's surface allows the helpers onlyintrospectIndexescalls, and it is one of them (its only caller). But the series carries "protected statics keep the hash-shadow family in the class" (cut 4's release6388161035), and cut 4's proposal for this cut kept it too, so it is left for the seat to price as its own slice (see the acceptance notes).parseIndexDdl,applyIndexKeyPartsand the typePhysicalIndex. All three live inschema-drift.ts, which exports them, so the module imports them from there (not a copy). After the movesql-driver.tsno longer reads the two functions, so they leave its./schema-drift.jsimport list;PhysicalIndexstays there, other members still read it. No declaration gains anexport.index.tsre-exports nothing from this module.[#25521 cut 5]paragraph, and the import comment insql-driver.tsis re-worded to nameintrospectIndexes. Both are comment-only.Overrides and spies, measured
TursoDriveroverridesintrospectIndexesand callssuper.introspectIndexes(tableName, opts)on its local arm. The class method is still there and hands the body its host.SqliteWasmDriveroverrides the getterisSqlite. The host reads it through a getter that reads the driver.sql-driver-12732-varchar-emitter-parity-wiring.test.tsspies onintrospectIndexeson the instance; that is still the class method.dist(not committed) gave 18 readings, identical at base and at head (diff empty). It covered: the SQLite answer for a table with a primary key, a composite UNIQUE constraint, a plain index, a partial unique index and an expression index (columns,partial,expressions,nullSafeColumns);getExistingIndexNames; a missing table; a failingPRAGMA index_infounder the default (rejects) and underonFailure: 'partial'(the short list); aknex.rawthat throws synchronously (the method still returns a promise that rejects, at both ends); a subclassintrospectIndexesthat callssuper; the MySQL arm through a subclass overriding the three dialect getters, with theEXPRESSIONfallback statement; a subclass override ofresolveHashShadowKeysand then an instance assignment of it (both reached); a rejectingresolveHashShadowKeys(surfaces by default, swallowed underpartial); and a subclassisSqlitegetter flipped between two calls (read at call time).The published
.d.tsdoes not changeUnder the series bar (ruling
6348891160, letter A), measured on basef00e8d5c8and headbd1670fe0, each built withpnpm --filter @objectstack/driver-sql buildagainst the same dependency tree (the base leg restores the two base files into this worktree after the cut commit, rebuilds, reads, then restores HEAD, proved by blob hash and an emptygit diff HEAD).dist/index.d.tsanddist/index.d.mts(no.d.cts); the two are identical at both ends.93da45168e82136b7613944525e47402d5dc6f9f8daa9efa4bdceeaa11b52a89(cuts 1-4's hash, unchanged).cmpbase vs head: identical, raw diff 0 lines, so the proof rests on raw identity and no normaliser is relied on.dist/index.d.ts: line 5714,protected introspectIndexes(tableName: string, opts?: {, withprotectedremoved, givescbaacf3c70282bd8dfc867c2f97d0f218b114c06b7fc11fbde5b03f5c05f9da0and a 4-line diff.d61a9dd3a02661602b1bb2dbe18152ac43986148f36b2746f40c0884bd8ffdecon all four (cut 4's value).dist/index.mjs29 to 30 host.call(sites,dist/index.js30 to 31.No changeset:
skip-changeset, per ruling6348891160item 4.Proof of move-only
getChildrenleaves, template pieces as their exact source text, comments and JSDoc compared line by line less leading whitespace). The moved function's parameters (less the addedthis), return type and body have the same token sequence as the base method, andasyncmatches. 673 body tokens compared, 0 differ; 2 parameters identical; return type identical.type = 'index'becomestype = 'indx'inside the SQLite arm'ssqlite_mastertemplate literal. The check then reports 1 token and 1 line different and exitsPROOF FAILED, exit 1.sql-driver.ts: 202 non-class statements at base and head; 200 byte-identical. The two others are the./schema-drift.jsimport (loses exactlyapplyIndexKeyPartsandparseIndexDdl) and the./sql-driver-introspection.jsimport (gains exactlyintrospectIndexes; its leading comment re-worded).IntrospectionHostare byte-identical at head (the first carries the re-worded header as leading trivia).IntrospectionHostkeeps its ten member lines and gains one. The two new statements are the./schema-drift.jsimport and the moved function.Readers of
sql-driver.tsby path, checked against the moved textNone needed an edit:
scripts/adr-anchors/packages__drivers__driver-sql__src__sql-driver.ts.jsoncarries ADR-0053 (formatOutput,presentReadValue) and ADR-0120 D4 (therecreate_indexceremony). Neither paragraph describes the moved body, so per card ask 3 no entry is owed. The moved body cites no ADR; the docblock's ADR-0048 mention stays on the class.check:adr-anchors: 85 anchored files at both ends; decision-letter citations on the anchored surface 1,847 at base and 1,847 at head.sql-driver.ts#introspectIndexes(git grepoverdocs/,content/,scripts/,.github/: 0 hits).check:adr-symbol-anchors: 2,474 anchors resolve at both ends.check:tenant-chokepoint. Rule 1 verdict and population unchanged (above). Rule 2 visits raw-family calls inSCAN_FILES; the moved body's fiveknex.raw(call sites (sqlite_master,PRAGMA index_list,PRAGMA index_info,pg_index, MySQLSTATISTICS) are catalog reads, none saysIS NULLagainst a tenant column (thepg_indexread saysix.indpred IS NOT NULL, not a tenant column). Verdict unchanged;.raw(call sites insql-driver.tsgo 75 to 70 (see the acceptance notes).check:logger-receiver-detach: 0 detaches at both ends.SqlDriver.introspectIndexes(schema-drift.ts,turso-driver.ts,packages/spec/src/contracts/schema-diff-service.ts) and the{@link introspectIndexes}references in the class still point at the method, which is still there.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 module included): 0 errors, 0 warnings. Repo-widepnpm lint(the seat asked for it; driver-sql declares no lint script): exit 0 at headbd1670fe0.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: 0 lost, 0 changed, 0 added.packages/drivers/driver-tursosuite, against the rebuilt driver-sqldistat each end: base 2,526 tests (2,492 passed, 0 failed, 34 skipped; 95 files), head the same; per name 0 / 0 / 0 (2,513 distinct names, 13 repeat).packages/drivers/driver-sqlite-wasmsuite: base 704 tests (704 passed; 39 files), head the same; per name 0 / 0 / 0.os-verify-lockcall,VERDICT command-exit 0at both ends.dispatch-gates --commandson this diff, at headbd1670fe0: 55 derived commands, each run with its exit code captured before any pipe.--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-closurefirst exited 3 (noobjectqldist) and exits 0 afterturbo run build --filter=@objectstack/objectql;check-plugin-teardown-shape --self-testfirst exited 3 on the shallow clone and exits 0 aftergit fetch --unshallow.check:commit-card-trailers --range origin/main..HEAD: 1 commit, clean.Acceptance notes
check:tenant-chokepointrule 2 reads 5 fewer raw call sites insql-driver.ts.SCAN_FILESnamessql-driver.tsand not the seam modules, so rule 2 no longer visits the five catalogknex.raw(calls that moved; the module now holds 24.raw(sites. None is an arm on a tenant column today, but a future edit that added one in the module would not be caught by rule 2. WideningSCAN_FILESis a gate edit and the open precondition the series carries for thegetBuilderareas; it is not made here.resolveHashShadowKeyscould follow. Its only caller is now the moved body, its body reads onlyknexand twoschema-drift.tsfunctions (no static), and its body (about 29 lines) is longer than the stub it would need (about 7), so it would pass the net-line rule at roughly -22. It stays because the series keeps the hash-shadow family in the class; whether it moves is the seat's call.applyDriftOpInPlace(14860) andrebuildSqliteTablePatched(14954), Schema sync. Neither builds throughgetBuilderand neither has athis.FIELD.delete/insert/update(site. Between them they readknex(14 times),logger(twice, socheck:logger-receiver-detachis the gate to watch on a host getter),dialectName,isMysql,isPostgres, and the methodsintrospectColumns,syncTableIndexes,resolveTenantField,nowColumnDefault,buildRebuiltColumn,applyIndexDriftOp,applyDeclaredColumnDefault, plus the fieldsmanagedObjectIndexesandmanagedObjectFields. That is a wide host; it should be priced against the net-line rule at its dispatch.TursoDriver'sintrospectIndexesoverride still callssuper.introspectIndexes(tableName, opts). That now returns the moved function's promise instead of anasyncmethod's promise. A caller awaits the same settlement, and a synchronous throw inside the body still arrives as a rejection (probe reading 6).Generated by Claude Code