Repository navigation
refactor(driver-sql): move applyDriftOpInPlace's and rebuildSqliteTablePatched's bodies out of sql-driver.ts into sql-driver-schema-sync.ts (#25521 cut 6) - #26041
Conversation
…iver-schema-sync.ts (#25521 cut 6) applyDriftOpInPlace and rebuildSqliteTablePatched move unedited into a new seam module; the class keeps both methods (docblock and signature less async), each handing its body one SchemaSyncHost literal. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P1g134P91q7EHTr6mTkQz7
📓 Docs Drift CheckThis PR changes 1 package(s): 13 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 6 release-owned page(s) also 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 f8275b991f48132e31578d44ecfa49c012201728 && git checkout f8275b991f48132e31578d44ecfa49c012201728
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 431f065177de0cfc9d682b3b18692132390e0c57 ebb210bf1b8013b2d5d6cf8eef1d7ad0f1fd7279 && git checkout -B drift-repro 431f065177de0cfc9d682b3b18692132390e0c57 && git merge --no-ff ebb210bf1b8013b2d5d6cf8eef1d7ad0f1fd7279
node scripts/docs-audit/affected-docs.mjs --json 431f065177de0cfc9d682b3b18692132390e0c57
|
席位核对ACCEPT · The maintainer's standing authorisation for landing reviewed PRs, verbatim: 「按照 pm-dispatch 规则复核过的都授权」.
Generated by Claude Code |
Requested by Leehom · project thread
Part of #25521
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Ruling-ref: 6348891160
Cut 6 of the
sql-driver.tssplit (#24586 ruling A, recorded in6270097840). The claim is6411690694. The bodies of the two in-place drift reconcilers of schema sync, the protectedSqlDriver#applyDriftOpInPlaceandSqlDriver#rebuildSqliteTablePatched, move unedited into a new seam module,packages/drivers/driver-sql/src/sql-driver-schema-sync.ts, and reach the class through one named host,SchemaSyncHost. Both methods keep their names, docblocks, signatures (lessasync) and positions.It is move-only, and the card stays open for the later cuts. Branch
claude/project-thread-hq3kec(platform-assigned to this card thread, as the claim records). The cut commit381a4bb77dsits onorigin/main05f7758f05;origin/mainwas then merged in (ebb210bf1b, merge basec16c00f930). The 17 commits it brought touch no driver package.Net line count (the seat's rule from ACCEPT
6385306916).sql-driver.tsgoes from 21,512 lines to 21,398: -114. The two bodies are 152 lines; the two stubs are 33 body lines, and the new import with its comment is 5. The new module is 227 lines.Serial with the file's in-flight PRs. Re-measured at my start: 20 open PRs, each file list read in full. None touches
packages/drivers/driver-sql/**,driver-turso/**ordriver-sqlite-wasm/**, except the Version Packages PR #25640, which touches only those packages'CHANGELOG.mdandpackage.json. Seat 1's #8740 (SqlDriver.upsert) has no open PR yet, and it is a different region;insertOnlyUpsertColumnsis not touched.The area, measured on
05f7758f05applyDriftOpInPlaceis lines 14859-14919 ofsql-driver.ts(one-line docblock, 58 body lines).rebuildSqliteTablePatchedis 14921-15049 (32-line docblock, 94 body lines). Both sit in the Schema sync section of cut 1's seam table, beside theapplyMigrationEntriesthat calls them (it stays).ManagedDriftEntrylist), so the inferred-return limit does not bite.getBuilder, socheck:tenant-chokepointrule 1 is untouched (24 bindings across 3 files at both ends).SqlDriver.read and no cast-wrappedthisread. The members they read are exactlyknex,logger,dialectName,isMysql,isPostgres,managedObjectFields,managedObjectIndexes, and the methodsapplyIndexDriftOp,introspectColumns,buildRebuiltColumn,nowColumnDefault,applyDeclaredColumnDefault,syncTableIndexesandresolveTenantField.this.FIELD.delete/insert/update(site: the one map read isthis.managedObjectFields.get(table).driver-sqlis outside the tenant-audit census corpus anyway (cut 1's reading).TursoDriverandSqliteWasmDriveroverride none of the two methods or the members they call (git grepover both packages'src, tests excluded: 0 overrides).The shape (#23050 shape B, as cuts 1-5 apply it)
asyncis dropped. Each body is now one host literal plus a.call(host, ...)of the moved function, marked[#25521 cut 6]. It returns the moved function's own promise, so a caller awaits the same settlement.SchemaSyncHostlists the 14 members above, each typed as the class member (an indexed access onSqlDriver). Each moved function types itsthisas the Pick of the host over exactly the members its body reads (6 and 10), and each stub annotates its literal as theThisParameterTypeof the moved function. There is no cast, and no member becomes public.knex,logger,managedObjectFieldsandmanagedObjectIndexes, the getterdialectNameand the two dialect getters go as GETTERS that read the driver at call time. The methods go as late-bound closures that call them on the driver, so a subclass override or an instance spy is still the one the body reaches.this.logger.warn(...)keeps its receiver: the getter hands back the driver's logger object andwarnis called on it (the cut 2 shape,rawStatementFault).isIndexDriftOpand the typesDriftOpandManagedDriftEntry. All three live inschema-drift.ts, which exports them, so the module imports them from there (not a copy).sql-driver.tsstill reads all three, so its import list does not change. No declaration gains anexport;index.tsre-exports nothing from the new module. The module imports only the typeSqlDriverfromsql-driver.ts, so there is no value cycle.Why
resolveHashShadowKeysstays (the open call this cut was handed)Measured: its body is 25 lines and reads only
knex(plusisHashShadowCarrierandparseHashShadowKeyPartsfromschema-drift.ts; no static), so a stub of about 6 lines would pay about -19. It stays in the class, for two reasons:introspectIndexesbody, so its home issql-driver-introspection.ts; moving it there would edit a second seam module in this PR, and moving it into the new module would put a catalog-read enrichment into the drift-apply module.knex, so carrying it would not shrink this cut's host; it is its own slice, priced on its own.It is proposed below as a small follow-up slice into
sql-driver-introspection.ts.Overrides and spies, measured
sql-driver-schema-drift.test.tscallsapplyDriftOpInPlaceon the driver after replacingknexandloggeron the instance; the getters read the replacements.sql-driver-unique-tenancy.test.tscallsrebuildSqliteTablePatchedon the driver.dist(not committed) gave 25 readings, identical at base and at head (diff empty). It covered: the honoured entries of a SQLite rebuild (relax and drop honoured, widen ignored, the same entry objects); an instance spy onintrospectColumns(reached once); a subclass overridingbuildRebuiltColumn,syncTableIndexes,nowColumnDefaultandresolveTenantField(each reached, the same calls); columns and rows after the rebuild; amanagedObjectFieldsmap replaced on the instance after construction (its default re-materialized); an index op routed to a subclassapplyIndexDriftOp; the SQLite unsupported-op warning through a logger replaced after construction, withthisbound to the logger; the Postgres arm through a subclassisPostgresgetter (six op types, the five statements and thefalse); the MySQL arm through a subclassisMysqlgetter (the restatedvarchar(40)and the missing-columnfalse); aknex.rawthat throws synchronously (still a rejected promise at both ends); and a failingsyncTableIndexesafter a rebuild (the samewarnline).The published
.d.tsdoes not changeUnder the series bar (ruling
6348891160, letter A), measured on base05f7758f05and head381a4bb77d, each built withpnpm --filter @objectstack/driver-sql buildagainst the same dependency tree (the base leg restores the basesql-driver.tsand removes the module in this worktree after the cut commit, under an EXIT/INT/TERM trap that restores HEAD; restore proved by blob hash and an emptygit diff HEAD). Re-read at the merged headebb210bf1b: the same.dist/index.d.tsanddist/index.d.mts(no.d.cts); the two are identical at every end.93da45168e82136b7613944525e47402d5dc6f9f8daa9efa4bdceeaa11b52a89(cuts 1-5's hash, unchanged).cmpbase vs head: identical, so the proof rests on raw identity and no normaliser is relied on.dist/index.d.ts: line 5604,protected applyDriftOpInPlace(op: DriftOp), withprotectedremoved, gives464af7349dba2db4f27756062df5297f44af8deeef3604276d10eee4e6059d9cand a 4-line diff.diff-identical)..call(hostsites indist/index.mjsanddist/index.jsgo 16 to 18.No changeset:
skip-changeset, per ruling6348891160item 4 (move-only, no product behaviour change).Proof of move-only
getChildrenleaves, string and template pieces as their exact source text; comments compared line by line less leading whitespace). For each moved function, the parameters (less the addedthis), return type and body have the same token sequence as the base method, andasyncmatches.applyDriftOpInPlace: 409 body tokens, 0 differ, 7 comments identical.rebuildSqliteTablePatched: 592 body tokens, 0 differ, 33 comments identical.PRAGMA foreign_keys = OFFbecomesPRAGMA foreign_keys = 0FF. The check then reports 1 token and 1 line different and exitsPROOF FAILED, exit 1.async.sql-driver.ts: 202 non-class statements at base, 203 at head; all 202 base statements byte-identical at head. The one new statement is the./sql-driver-schema-sync.jsimport with its four-line comment.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, which lives inapplyIndexDriftOpand stays). Neither paragraph describes a moved body, so per card ask 3 no entry is owed. The moved bodies cite no ADR.check:adr-anchors: 87 anchored files at both ends; decision-letter citations on the anchored surface 1,864 at base (c16c00f930, clean detached worktree) and 1,864 at head (ebb210bf1b).sql-driver.ts#applyDriftOpInPlaceor#rebuildSqliteTablePatched(git grepoverdocs/,content/,scripts/,.github/: 0 hits).check:adr-symbol-anchors: 2,658 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 bodies' 13 raw calls (the Postgres and MySQLALTER TABLEstatements, the twoPRAGMA foreign_keystoggles and the rebuild'sINSERT ... SELECT) are DDL and a copy; none saysIS NULLagainst a tenant column. Verdict unchanged;.raw(call sites insql-driver.tsgo 70 to 57 (see the acceptance notes).check:logger-receiver-detach: 0 detaches at both ends (3,717 files walked at base, 3,719 at head: the new module and the gitignored generatedpackages/spec/src/migrations/registry.ts, which the unbuilt base worktree lacks).logger-receiver-detach.test.ts③ scanssql-driver.tsonly; the two movedthis.logger.warn(calls are direct calls, and the repo-wide gate covers the new module (cut 2's reading).sql-driver-11321-sqlite-audit-default-canonical.test.ts,sql-driver-11722-sqlite-rebuild-applied-honesty.test.ts,schema-drift.ts) and the{@link rebuildSqliteTablePatched}references in the class still point at the methods, which are still there. No test reads either body as source text.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: 266 files (the new module included), 0 errors, 0 warnings, exit 0.os-verify-lockcall, exit 0 at every end. Compared per test name and status from vitest's JSON reporter, base05f7758f05vs head381a4bb77d, and again vs the merged headebb210bf1b:packages/drivers/driver-sql: 3,999 tests (3,787 passed, 0 failed, 212 skipped; 247 files) at every end; 0 lost, 0 changed, 0 added.packages/drivers/driver-turso, against that end's built driver-sqldist: 2,526 tests (2,492 passed, 0 failed, 34 skipped; 95 files); 0 / 0 / 0 (2,513 distinct names).packages/drivers/driver-sqlite-wasm: 704 tests (704 passed; 39 files); 0 / 0 / 0.dispatch-gates --commandson this diff at the merged headebb210bf1b(merge basec16c00f930, no STALE TREE): 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:adr-anchors,check:adr-symbol-anchors,check:authz-resolver,check:error-code-casing,check:filter-alias-parity(rosters underpackages/),check:commit-card-trailersand its--range origin/main..HEAD(2 commits, clean): all exit 0.Acceptance notes
check:tenant-chokepointrule 2 reads 13 fewer raw call sites insql-driver.ts.SCAN_FILESnamessql-driver.tsand not the seam modules, so rule 2 no longer visits the moved DDL calls; the new module holds 13.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.resolveHashShadowKeysintosql-driver-introspection.tsbeside its only caller (about -19;IntrospectionHostalready lists it andknex). (b) The rest of the drift-apply family next to this pair,applyIndexDriftOp(~14719) andrestoreBareIndexAfterFailedTighten(~14836), into this cut's module: neither builds throughgetBuilder; both should be screened for statics and priced against the net-line rule at dispatch, andapplyIndexDriftOpcarries the ADR-0120 D4 ceremony, so its anchor entry paragraph would follow it into a new entry for the module.asyncmethods. A caller awaits the same settlement, and a synchronous throw inside a body still arrives as a rejection (probe reading above).Generated by Claude Code