Repository navigation
Commit c1ae4a4
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X6RcybLaAtijgtf3Zm7ot2z)_
Part of #25521
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Ruling-ref: 6348891160
Cut 6 of the `sql-driver.ts` split (#24586 ruling A, recorded in
`6270097840`). The claim is `6411690694`. The bodies of the two in-place
drift reconcilers of schema sync, the protected
`SqlDriver#applyDriftOpInPlace` and
`SqlDriver#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 (less `async`) 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 commit `381a4bb77d` sits on `origin/main`
`05f7758f05`; `origin/main` was then merged in (`ebb210bf1b`, merge base
`c16c00f930`). The 17 commits it brought touch no driver package.
**Net line count (the seat's rule from ACCEPT `6385306916`).**
`sql-driver.ts` goes 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/**` or
`driver-sqlite-wasm/**`, except the Version Packages PR #25640, which
touches only those packages' `CHANGELOG.md` and `package.json`. Seat 1's
#8740 (`SqlDriver.upsert`) has no open PR yet, and it is a different
region; `insertOnlyUpsertColumns` is not touched.
## The area, measured on `05f7758f05`
- `applyDriftOpInPlace` is lines 14859-14919 of `sql-driver.ts`
(one-line docblock, 58 body lines). `rebuildSqliteTablePatched` is
14921-15049 (32-line docblock, 94 body lines). Both sit in the Schema
sync section of cut 1's seam table, beside the `applyMigrationEntries`
that calls them (it stays).
- Both are protected with annotated return types (a promise of a
boolean, and a promise of the honoured `ManagedDriftEntry` list), so the
inferred-return limit does not bite.
- Neither builds through `getBuilder`, so `check:tenant-chokepoint` rule
1 is untouched (24 bindings across 3 files at both ends).
- Neither reads a static: an AST screen of the two bodies finds no
`SqlDriver.` read and no cast-wrapped `this` read. The members they read
are exactly `knex`, `logger`, `dialectName`, `isMysql`, `isPostgres`,
`managedObjectFields`, `managedObjectIndexes`, and the methods
`applyIndexDriftOp`, `introspectColumns`, `buildRebuiltColumn`,
`nowColumnDefault`, `applyDeclaredColumnDefault`, `syncTableIndexes` and
`resolveTenantField`.
- Neither has a `this.FIELD.delete/insert/update(` site: the one map
read is `this.managedObjectFields.get(table)`. `driver-sql` is outside
the tenant-audit census corpus anyway (cut 1's reading).
- `TursoDriver` and `SqliteWasmDriver` override none of the two methods
or the members they call (`git grep` over both packages' `src`, tests
excluded: 0 overrides).
## The shape (#23050 shape B, as cuts 1-5 apply it)
- The class keeps both methods, docblock included, byte-identical except
that `async` is 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.
- `SchemaSyncHost` lists the 14 members above, each typed as the class
member (an indexed access on `SqlDriver`). Each moved function types its
`this` as the Pick of the host over exactly the members its body reads
(6 and 10), and each stub annotates its literal as the
`ThisParameterType` of the moved function. There is no cast, and no
member becomes public.
- The fields `knex`, `logger`, `managedObjectFields` and
`managedObjectIndexes`, the getter `dialectName` and 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 and `warn` is called on it (the cut 2 shape,
`rawStatementFault`).
- **Module-level declarations.** The bodies read `isIndexDriftOp` and
the types `DriftOp` and `ManagedDriftEntry`. All three live in
`schema-drift.ts`, which exports them, so the module imports them from
there (not a copy). `sql-driver.ts` still reads all three, so its import
list does not change. No declaration gains an `export`; `index.ts`
re-exports nothing from the new module. The module imports only the type
`SqlDriver` from `sql-driver.ts`, so there is no value cycle.
- The move was produced by a script from the source text, not retyped:
each body line re-indented two columns. Neither body holds a multi-line
template literal, so no line keeps its base indentation.
### Why `resolveHashShadowKeys` stays (the open call this cut was
handed)
Measured: its body is 25 lines and reads only `knex` (plus
`isHashShadowCarrier` and `parseHashShadowKeyParts` from
`schema-drift.ts`; no static), so a stub of about 6 lines would pay
about -19. It stays in the class, for two reasons:
- **The claim's file surface names one new or existing seam module.**
Its only caller is cut 5's `introspectIndexes` body, so its home is
`sql-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.
- **It shares nothing with this pair** but `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.ts` calls `applyDriftOpInPlace` on the
driver after replacing `knex` and `logger` on the instance; the getters
read the replacements. `sql-driver-unique-tenancy.test.ts` calls
`rebuildSqliteTablePatched` on the driver.
- A scratch probe against the built `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 on `introspectColumns`
(reached once); a subclass overriding `buildRebuiltColumn`,
`syncTableIndexes`, `nowColumnDefault` and `resolveTenantField` (each
reached, the same calls); columns and rows after the rebuild; a
`managedObjectFields` map replaced on the instance after construction
(its default re-materialized); an index op routed to a subclass
`applyIndexDriftOp`; the SQLite unsupported-op warning through a logger
replaced after construction, with `this` bound to the logger; the
Postgres arm through a subclass `isPostgres` getter (six op types, the
five statements and the `false`); the MySQL arm through a subclass
`isMysql` getter (the restated `varchar(40)` and the missing-column
`false`); a `knex.raw` that throws synchronously (still a rejected
promise at both ends); and a failing `syncTableIndexes` after a rebuild
(the same `warn` line).
## The published `.d.ts` does not change
Under the series bar (ruling `6348891160`, letter A), measured on base
`05f7758f05` and head `381a4bb77d`, each built with `pnpm --filter
@objectstack/driver-sql build` against the same dependency tree (the
base leg restores the base `sql-driver.ts` and 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 empty `git diff
HEAD`). Re-read at the merged head `ebb210bf1b`: the same.
- This package emits `dist/index.d.ts` and `dist/index.d.mts` (no
`.d.cts`); the two are identical at every end.
- Raw sha256 of both files at base, head and merged head:
`93da45168e82136b7613944525e47402d5dc6f9f8daa9efa4bdceeaa11b52a89` (cuts
1-5's hash, unchanged). `cmp` base vs head: identical, so the proof
rests on raw identity and no normaliser is relied on.
- Positive control on a copy of the head `dist/index.d.ts`: line 5604,
`protected applyDriftOpInPlace(op: DriftOp)`, with `protected` removed,
gives `464af7349dba2db4f27756062df5297f44af8deeef3604276d10eee4e6059d9c`
and a 4-line diff.
- Export tables: the ESM and CJS bundles each export the same 56 names
at base, head and merged head (sorted lists `diff`-identical).
- The head build carries the move: `.call(host` sites in
`dist/index.mjs` and `dist/index.js` go 16 to 18.
No changeset: `skip-changeset`, per ruling `6348891160` item 4
(move-only, no product behaviour change).
## Proof of move-only
- **Body, by AST token** (recursive `getChildren` leaves, 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 added `this`), return type and body have the same token
sequence as the base method, and `async` matches. `applyDriftOpInPlace`:
409 body tokens, 0 differ, 7 comments identical.
`rebuildSqliteTablePatched`: 592 body tokens, 0 differ, 33 comments
identical.
- **Lines**: 156 lines of the two bodies compared (closing braces
included); every one is the base line with two leading spaces removed.
- **Negative control**: in a copy of the module, `PRAGMA foreign_keys =
OFF` becomes `PRAGMA foreign_keys = 0FF`. The check then reports 1 token
and 1 line different and exits `PROOF FAILED`, exit 1.
- **Class side**: 347 members at base and head, in the same order. The
345 that did not move are byte-identical to base, leading trivia
included. Each stub's leading trivia and signature equal the base's,
less `async`.
- **Top level of `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.js` import with its four-line
comment.
- **Size**: +267 / -154 over 2 files, far under the 3,000-line
manual-merge line.
## Readers of `sql-driver.ts` by path, checked against the moved text
None needed an edit:
- **ADR anchors.**
`scripts/adr-anchors/packages__drivers__driver-sql__src__sql-driver.ts.json`
carries ADR-0053 (`formatOutput`, `presentReadValue`) and ADR-0120 D4
(the `recreate_index` ceremony, which lives in `applyIndexDriftOp` and
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`)**.
- **Symbol anchors.** No ADR, checklist or doc anchors
`sql-driver.ts#applyDriftOpInPlace` or `#rebuildSqliteTablePatched`
(`git grep` over `docs/`, `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 in `SCAN_FILES`; the moved
bodies' 13 raw calls (the Postgres and MySQL `ALTER TABLE` statements,
the two `PRAGMA foreign_keys` toggles and the rebuild's `INSERT ...
SELECT`) are DDL and a copy; none says `IS NULL` against a tenant
column. Verdict unchanged; `.raw(` call sites in `sql-driver.ts` go 70
to 57 (see the acceptance notes).
- **Logger receivers.** `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 generated `packages/spec/src/migrations/registry.ts`,
which the unbuilt base worktree lacks). `logger-receiver-detach.test.ts`
③ scans `sql-driver.ts` only; the two moved `this.logger.warn(` calls
are direct calls, and the repo-wide gate covers the new module (cut 2's
reading).
- **Test comments** that name the two methods
(`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-conformance` at base and head: **55 covered, 0 in the
DEBT ledger, 0 exempt, both times.**
## Verification
- `tsc --noEmit` (driver-sql) exit 0. `eslint --no-inline-config` over
`packages/drivers/driver-sql/src`: 266 files (the new module included),
0 errors, 0 warnings, exit 0.
- Each suite ran under its own `os-verify-lock` call, exit 0 at every
end. Compared per test name and status from vitest's JSON reporter, base
`05f7758f05` vs head `381a4bb77d`, and again vs the merged head
`ebb210bf1b`:
- `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-sql
`dist`: 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 --commands` on this diff at the merged head
`ebb210bf1b` (merge base `c16c00f930`, no STALE TREE): 55 derived
commands, each run with its exit code captured before any pipe. `--ran`
reconciles 55 derived, 54 run, 1 NOT MEASURED, 0 unrun. The NOT MEASURED
one is `check:dual-build-cjs-loads` (exit 3, PREREQUISITE NOT MET: it
needs every package's `dist`), which CI runs. `check:lean-entry-closure`
first exited 3 (no `objectql` dist) and exits 0 after `turbo run build
--filter=@objectstack/objectql`.
- Also run, outside the derivation: `check:adr-anchors`,
`check:adr-symbol-anchors`, `check:authz-resolver`,
`check:error-code-casing`, `check:filter-alias-parity` (rosters under
`packages/`), `check:commit-card-trailers` and its `--range
origin/main..HEAD` (2 commits, clean): all exit 0.
- No reverse verification or ablation: the diff changes no tested
behaviour.
## Acceptance notes
- **`check:tenant-chokepoint` rule 2 reads 13 fewer raw call sites in
`sql-driver.ts`.** `SCAN_FILES` names `sql-driver.ts` and 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.
Widening `SCAN_FILES` is a gate edit and the open precondition the
series carries for the `getBuilder` areas; it is not made here.
- **Proposed next slices.** (a) `resolveHashShadowKeys` into
`sql-driver-introspection.ts` beside its only caller (about -19;
`IntrospectionHost` already lists it and `knex`). (b) The rest of the
drift-apply family next to this pair, `applyIndexDriftOp` (~14719) and
`restoreBareIndexAfterFailedTighten` (~14836), into this cut's module:
neither builds through `getBuilder`; both should be screened for statics
and priced against the net-line rule at dispatch, and
`applyIndexDriftOp` carries the ADR-0120 D4 ceremony, so its anchor
entry paragraph would follow it into a new entry for the module.
- The class methods now return the moved functions' promises instead of
being `async` methods. 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](https://claude.ai/code/session_01P1g134P91q7EHTr6mTkQz7)_
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8a990d8 commit c1ae4a4
2 files changed
Lines changed: 267 additions & 154 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
0 commit comments