Repository navigation
Commit d7f76b6
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1XCTPWahtfVNDqaZ7ZjxvNs5)_
Part of #25521
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Ruling-ref: 6348891160
## 维护者速读
- **改了什么**:把 `sql-driver.ts`
里「字段默认值在建表语句里写成什么」这一个机制的两个方法体(`nowColumnDefault`:`defaultValue: 'NOW()'`
在各数据库方言下的列默认值;`applyDeclaredColumnDefault`:判断一个字段的 `defaultValue`
该不该、以什么形式成为列默认值)原样搬进已有的
`sql-driver-schema-sync.ts`;类上两个方法全部保留,只把方法体转交过去,`SchemaSyncHost`
一个成员都不用加。
- **为什么改**:#25521 拆分超大文件的第 19 刀;第 18
刀合入后重新测量,这是仍成「一个机制」、收益最大且不碰任何系列限制的区域,`sql-driver.ts` 减少 41 行。
- **风险与回滚**:纯搬移,无行为变化;三个 SQL 驱动的测试两端逐条一致,公开类型声明哈希不变,149 条探针读数两端一致(仅 1
条栈顶接收者名不同)。回滚即还原本 PR。
- **先看**:`sql-driver-schema-sync.ts` 头注释新增的第 19
刀段落与文件末尾两个函数;`sql-driver.ts` 中两个方法的转交桩;`sql-driver.ts` 里
`MYSQL_DATETIME_PRECISION`、`isNowDefaultValue` 两处就地加 `export`。
- **两分钟验证**:`pnpm --filter @objectstack/driver-sql exec vitest run
src/sql-driver-user-datetime-default-format.test.ts
src/sql-driver-option-default-ddl.test.ts
src/sql-driver-21241-mysql-now-default-precision.test.ts
src/sql-driver-11550-dialect-client-spellings.test.ts`,预期全部通过。
- **需要你做的**:无,席位落地。
## What changes
Cut 19 of the `sql-driver.ts` split (#24586 ruling A, recorded in
`6270097840`). The claim is `6454724955`. Cut 18 (#26894) merged first,
as `452325eed9`; this cut opens with a fresh seam table taken on
`origin/main` `4049efa345` (below) and takes the largest area that is
one mechanism and moves cleanly: the **declared column DEFAULT
emission**, from the class's `Internal helpers › Column creation helper`
sub-banner. Its two bodies move unedited into the **existing** seam
module `packages/drivers/driver-sql/src/sql-driver-schema-sync.ts`,
through its host `SchemaSyncHost`:
- `nowColumnDefault`, the driver-native column DEFAULT for a
`defaultValue: 'NOW()'` field, per dialect and per `date` / `time` /
`datetime` type (the UTC expression defaults of #3994 and #4022, the
MySQL `DATETIME(3)` precision of #21241, the canonical SQLite `strftime`
forms);
- `applyDeclaredColumnDefault`, the one place that decides what a
field's `defaultValue` becomes in DDL (`NOW()` through
`nowColumnDefault`; a runtime token such as `current_user` emits
nothing, #4560; an expression envelope emits nothing; a literal is
emitted verbatim).
The SQLite table rebuild that cut 6 moved into this module
(`rebuildSqliteTablePatched`) already reaches both through
`SchemaSyncHost`, which already lists both members and every member
their bodies read, so **the host does not grow**. `createColumn` (pinned
in place) and `createAuditTimestampColumn`, the other callers, stay in
the class and still call the two methods on the driver.
**Module-level declarations.** None moves. The bodies read three:
- `MYSQL_DATETIME_PRECISION` and `isNowDefaultValue` are declared in
`sql-driver.ts`, which still reads both (`createAuditTimestampColumn`,
`createColumn`, the MySQL widenings). Each gains `export` in place, and
the module imports them from `./sql-driver.js` through its existing
import line. `index.ts` names its re-exports one by one and names
neither, so the published surface does not move (measured below).
- `isRuntimeDefaultToken` comes from `@objectstack/spec/data`. Its only
reader in `sql-driver.ts` moved, so it leaves that import line
(`isNowDefaultToken` stays there), and the module adds it to its
existing `@objectstack/spec/data` import.
- The moved signatures name `Knex.Raw` and `Knex.ColumnBuilder`, so the
module gains `import type { Knex } from 'knex';` (erased;
`sql-driver-autonumber.ts` has the same line).
The change is move-only, and the card stays open for later cuts. There
is no `docs/adr/**` edit, no `packages/spec/**` edit, no anchor entry
change, no gate edit, no test edit and no new gate. Branch
`claude/project-thread-1nvx81` (the platform assigned it to this card
thread, as the claim records). The move is one commit, `fe7fb7ec5`, on
`4049efa345`, followed by one merge of `origin/main` (`aa00362fe5`, 12
commits, none in `packages/drivers/**`); the head is `79ca88b71b`.
**Net line count (the seat's rule).** `sql-driver.ts` goes from 18,447
lines to 18,406: **-41**.
- **Out:** the two bodies, 60 lines plus their closing braces (51 + 9).
- **In:** the two stub bodies, 19 lines with their closing braces (13 +
6), and 2 comment lines above the existing `sql-driver-schema-sync.js`
import, whose one line gains the two names. The `@objectstack/spec/data`
token import and the two `export` additions change lines in place.
- `sql-driver-schema-sync.ts` goes from 2,066 to 2,148 lines (+82): the
two functions with their one-line docblocks, a 13-line header paragraph
and the `knex` type import. `SchemaSyncHost` is unchanged (80 members).
**Path readers.** No test, script, doc, ADR or anchor entry reads either
body by path, so none is migrated (screen below).
**Serial with the file's in-flight PRs.** I read the file list of every
open PR on `objectstack-ai/objectstack` at the start (39) and again
before opening this one (30). None touches `sql-driver.ts`,
`sql-driver-schema-sync.ts`, `turso-driver.ts`, `sqlite-wasm-driver.ts`,
`check-tenant-chokepoint.mjs` or a driver-sql anchor entry; #26556
(dependabot) touches only the three drivers' `package.json`.
## Seam table, fresh, on `4049efa345`
- **Size and churn.** `sql-driver.ts` is 18,447 lines. The 30-day column
counts `git blame` lines from commits on or after 2026-09-27T21:44:05Z,
30 days before the base commit. `scripts/pm/git-history.mjs count`
proves 32 commits on the file in 30 days and 4 in the last 7
(first-parent `origin/main`, history deepened to cover the window). In
all, 3,412 lines (18.5%) are from the last 30 days.
- **Class shape.** `SqlDriver` spans lines 4245-18372 with 350 members:
243 instance methods, 13 accessors and 32 statics, all 32 private or
protected.
- **How it was measured.** The same TypeScript compiler AST script cuts
9-18 used, which strips casts, parentheses, `!` and `satisfies` before
it reads `this`. Sections are the class's own banner comments.
| Lines | Section | First … last member | Lines | 30-day | Methods
(public) | Inferred public | getBuilder sites | Statics
(private/protected) |
|:--|:--|:--|--:|--:|:--|--:|--:|:--|
| 1-4244 | Module preamble | - | 4,244 | 695 | - | - | - | - |
| 4245-5836 | Class head: fields, statics, constructor, capability
getters | `name` … `assertDialectEmits` | 1,592 | 290 | 8 (1) | 1 | 0 |
18 (18) |
| 5837-6268 | Lifecycle | `connect` … `disconnect` | 432 | 155 | 8 (3) |
0 | 0 | 6 (6) |
| 6269-8675 | CRUD — IDataDriver core | `find` … `delete` | 2,407 | 745
| 43 (7) | 0 | 12 | 0 (0) |
| 8676-9205 | Bulk & Batch Operations | `bulkCreate` … `count` | 530 |
70 | 9 (6) | 0 | 7 | 0 (0) |
| 9206-9302 | Raw Execution | `rawStatementFault` …
`noteRuntimeIndexDdl` | 97 | 28 | 3 (1) | 0 | 0 | 0 (0) |
| 9303-9395 | Transactions | `beginTransaction` … `rollbackTransaction`
| 93 | 46 | 7 (5) | 0 | 0 | 0 (0) |
| 9396-9892 | Aggregation | `aggregate` …
`unresolvableAggregateColumnRefusal` | 497 | 70 | 5 (1) | 0 | 1 | 0 (0)
|
| 9893-10154 | Distinct | `distinct` …
`unresolvableDistinctColumnRefusal` | 262 | 26 | 3 (1) | 0 | 1 | 0 (0) |
| 10155-10270 | Window Functions | `findWithWindowFunctions` …
`findWithWindowFunctions` | 116 | 4 | 1 (1) | 0 | 1 | 0 (0) |
| 10271-10369 | Query Plan Analysis | `explain` … `analyzeQuery` | 99 |
1 | 2 (2) | 0 | 1 | 0 (0) |
| 10370-10428 | Schema Sync (syncSchema / init) | `syncSchema` …
`reclaimSpace` | 59 | 34 | 3 (3) | 0 | 0 | 0 (0) |
| 10429-11853 | Schema Sync (syncSchema / init) › Data-lifecycle
rotation (ADR-0057 P2) | `rotationStateByTable` …
`migrateMysqlTimeColumns` | 1,425 | 219 | 26 (4) | 0 | 0 | 0 (0) |
| 11854-12034 | Schema Sync (syncSchema / init) › Deferred schema DDL
(#3917) | `setDeferredDdl` … `flushDeferredSchemaDdl` | 181 | 46 | 6 (4)
| 0 | 0 | 0 (0) |
| 12035-12849 | Schema Sync (syncSchema / init) › Managed-schema drift &
reconcile (#2186) | `dialectName` … `createNullSafeUniqueIndex` | 815 |
237 | 23 (3) | 0 | 0 | 0 (0) |
| 12850-12901 | Schema Introspection | `listPhysicalColumns` …
`introspectSchema` | 52 | 46 | 2 (2) | 0 | 0 | 0 (0) |
| 12902-13172 | Internal helpers | `getKnex` … `auditMissingTenant` |
271 | 73 | 8 (1) | 0 | 1 | 0 (0) |
| 13173-15222 | Internal helpers › Filter helpers |
`tableNameForBuilder` … `applyFalseConstant` | 2,050 | 331 | 44 (2) | 0
| 0 | 0 (0) |
| 15223-15398 | Internal helpers › Field mapping | `mapSortField` …
`mapAggregateFunc` | 176 | 2 | 6 (0) | 0 | 0 | 0 (0) |
| 15399-15446 | Internal helpers › Window function builder |
`buildWindowFunction` … `buildWindowFunction` | 48 | 26 | 1 (0) | 0 | 0
| 0 (0) |
| 15447-17393 | Internal helpers › Column creation helper |
`nowColumnDefault` … `applyDeclaredColumnDefault` | 1,947 | 92 | 19 (0)
| 0 | 0 | 8 (8) |
| 17394-17691 | Internal helpers › Database helpers | `sqliteFilename` …
`isJsonField` | 298 | 76 | 9 (2) | 0 | 0 | 0 (0) |
| 17692-18168 | Internal helpers › SQLite serialisation | `formatInput`
… `formatOutput` | 477 | 27 | 2 (0) | 0 | 0 | 0 (0) |
| 18169-18372 | Internal helpers › Introspection internals |
`introspectColumnOrder` … `introspectUniqueConstraints` | 204 | 73 | 5
(0) | 0 | 0 | 0 (0) |
| 18373-18447 | After the class | - | 75 | 0 | - | - | - | - |
### Pricing the areas
Eligibility is as cuts 11-18 defined it: an annotated return type or not
public; no `getBuilder`, `this.FIELD.delete/insert/update(`,
private-static, `super`, bare-`this` or `this`-write site; not
`insertOnlyUpsertColumns`; not a member pinned in place (`createColumn`,
`applyFilterCondition`, `formatInput`/`formatOutput`, `initObjects`,
`ensureShardTable`, `computeTenantField`,
`migrateMysqlDatetimeColumns`/`migrateMysqlTimeColumns`,
`compileFilters`). Each area is priced as its stubs minus its bodies,
then net of the module-level declarations only it reads and of its
import edits. The two leading rows were measured by running the move
script on a scratch copy of the base file; the rest are the stub
estimate (a stub costs 4 lines, +2 per field read, +1 per method read).
Cut 18 priced the largest clean single area at about -62, naming two
candidates: the class head's date-bucket/query-timing pair and the
column-creation remainder. Re-measured, neither is one mechanism: each
-62 is the sum of a sub-banner's movable members, the same kind of sum
as the filter-helper remainder this series does not stitch. So I priced
mechanism by mechanism.
| Area | Bodies | Bodies net | Declarations and imports | Disposition |
|:--|--:|--:|--:|:--|
| **Declared column DEFAULT emission** (`nowColumnDefault` -39,
`applyDeclaredColumnDefault` -4) | 2 | -43 (measured) | 0 declarations
move (2 gain `export` in place); +2 for the import comment | **Moves
(this cut).** -41 measured. |
| Date bucketing (`buildDateBucketExpr`) | 1 | -42 (measured) | No
existing seam module fits it: a new module costs an import line plus its
comment, +3 | **Runner-up**, about -39. Not taken: smaller. It reads the
`dateGranularityCapabilities` accessor and `sqliteTemporalArg` /
`temporalFieldKind`, all of which stay. |
| Presumed-timestamp update (`updateWithPresumedTimestamp` -31,
`resolveUpdatedAtColumnPresence` -6) | 2 | -37 | +2 or more for the
import comment | Not taken: smaller (about -35).
`attemptWithoutPoisoning` is shared with the autonumber module and is a
separate mechanism. |
| Column creation remainder as a whole (the two above, plus
`schemaBytesPerChar` -9, `rethrowWithRowSizeExplanation` -2,
`decorateHashShadowDuplicate` -8) | 5 | -62 | | Not taken whole: three
mechanisms (column DEFAULT, the row-size refusal's explanation, the
hash-shadow duplicate's explanation). The other two pay -11 and -8. The
other 13 members of that sub-banner read private statics or are pinned.
|
| Class head pair (`buildDateBucketExpr` -42, `installQueryTiming` -20)
| 2 | -62 | 0 | Not taken whole: two unrelated mechanisms; date
bucketing alone is the runner-up above. |
| Filter helpers remainder (14 small members, largest `presentReadValue`
-29) | 14 | -80 | | Not taken: four mechanisms of -29 or less each,
which the order says not to stitch. `compileFilters` (-75) is refused
(inferred return type). |
| `Internal helpers` tenant members (`auditMissingTenant` -26,
`applyTenantScope` -25, `getBuilder` -5, `injectTenantOnInsert` -2) | 4
| -58 | | Not taken: `applyTenantScope` holds 2 of the file's 4 D8
predicates and `getBuilder` is the builder itself, which
`check:tenant-chokepoint` reads only in `sql-driver.ts` (series limit).
|
| Window function builder (`buildWindowFunction`), field mapping
(`orderKeysFor`), database helpers (`ensureDatabaseExists`,
`sqliteFilename`) | 1 / 1 / 2 | -28 / -27 / -27 | | Below -30 each. |
## Why
### Why this area, as one area
- **One mechanism.** The two answer one question, "what does a field's
declared `defaultValue` become in the DDL of a fresh or rebuilt column",
and `applyDeclaredColumnDefault` is how a declared field's `NOW()`
reaches `nowColumnDefault`. They go beside the SQLite rebuild that
already calls both through the host. The other callers of
`nowColumnDefault` (the audit-column DDL, the MySQL datetime widening,
the rebuild's audit columns) still call the method on the driver.
- **It pays the most of any single mechanism that moves cleanly.** Date
bucketing (-42 in bodies) is within one line of it in bodies, but needs
a new module and its import line; this area joins a module whose import
line and host already exist.
- **What stays, and why.** `createAuditTimestampColumn` (its stub would
cost more than its body) and the rest of the `Column creation helper`
sub-banner: the hash-shadow and varchar-width members read private
statics, `createColumn` is pinned, and the row-size and hash-shadow
explanations are other mechanisms.
- **No series limit is touched.** Neither body builds through
`getBuilder`, reads a static, has a `this.FIELD.delete/insert/update(`
site, uses `super` or a bare `this`, or assigns to `this`. Both are
protected with annotated returns (`Knex.Raw`, `void`).
`check:tenant-chokepoint`'s D8 predicates, measured with its own
`nullArmsOf`: **4 at base and 4 at head**, all in `sql-driver.ts`, 0 in
the moved bodies.
- **Durability gate.** Neither body has a `try` or calls
`logDurabilityFailure`. `check:durability-log-level --list` prints 164
lines at both ends, identical except that two `runWideningAlters` seams
in `sql-driver.ts` move 2 lines down (the import comment).
- **Subclasses.** `TursoDriver` and `SqliteWasmDriver` override neither
method; `remote-transport.ts` names `applyDeclaredColumnDefault` in
prose, which is still true. Tests that widen the class (the CLI's
`generate-declared-column-default.pin.test.ts` oracle and four
driver-sql suites) call `this.nowColumnDefault(type)` on a subclass
instance, which still reaches the same body.
- **Path readers, screened.** No script, test, doc or ADR names either
member by a `sql-driver.ts#…` pointer or a `sql-driver.ts::…` key, and
no `scripts/adr-anchors/**` record names them. ADR-0053 names
`nowColumnDefault` in prose, still true.
## The shape (#23050 shape B, as cuts 1-18 apply it)
- Each class method keeps its docblock and signature, byte-identical.
Its body is now one host literal plus `NAME.call(host, ...)`, marked
`[#25521 cut 19]`. Both methods are synchronous at both ends, so a
failure is still a synchronous throw (probe reading 7).
- The fields `nowColumnDefault` reads (`isMysql`, `isPostgres`,
`isSqlite`, `knex`) go as GETTERS that read the driver at call time. The
method `applyDeclaredColumnDefault` calls (`nowColumnDefault`) goes as a
closure that calls the method on the driver at call time. So a subclass
override, an instance spy, or a field replaced after construction is
still the one the body reaches (probe readings 2, 5, 6).
- **Comments.** The module header gains one `[#25521 cut 19]` paragraph
saying what moved, what stayed and where each read declaration comes
from. The `sql-driver.ts` import comment names cut 19 in 2 lines.
Neither cites an `ADR-NNNN` letter. Both stubs keep their docblocks
(which mention ADR-0074 and #4560/#7246) in `sql-driver.ts`.
- **How the move was made.** A script produced it from the source text;
nothing was retyped. Each body line is re-indented two columns; no body
line starts inside a template literal.
## Verification
### ADR anchors
- **The count.** `check:adr-anchors` counts **1897** decision-letter
citations at base `4049efa345` (a clean detached worktree) and **1897**
at the move commit, over 91 anchored files at both ends; the two outputs
are byte-identical. Both runs exit 0.
- **Why equal.** No comment inside the moved bodies or the new header
paragraph cites a decision letter.
- **No entry needs a new home.** No anchor entry names a moved member.
`check:adr-symbol-anchors`: 2687 resolve at both ends (output
byte-identical).
- **After the merge.** `main` moved under the cut, and its own commits
changed the count, so I measured its tip `aa00362fe5` (a clean detached
worktree) against the merge head `79ca88b71b`: **1896** letters at both,
exit 0 both, and 2687 symbol anchors resolve at both.
### The published `.d.ts` does not change
This is measured under the series bar (ruling `6348891160`, item 1).
- **How each end was built.** `pnpm turbo run build
--filter=@objectstack/driver-sql --force` at each end, against the same
dependency tree. The base leg writes base `sql-driver.ts` and base
`sql-driver-schema-sync.ts` into this worktree under an EXIT/INT/TERM
trap that restores HEAD. The restore is proved by the HEAD blob hashes,
an empty `git diff HEAD` and 0 status entries (`RESTORE-OK 1084637…
8b345d7…`).
- **The hashes.** The raw sha256 of `dist/index.d.ts` and
`dist/index.d.mts` is the same at base, at the move commit and at the
merge head:
`0f33bf3febaac3c7aa96f68a4226d752766b8203ab7acade523b69f9aaa44d74`
(unchanged since cut 8). These two are the dist's only declaration files
(no chunk), so the declaration-reorder bar of ruling `6441032442` does
not come into play.
- **Positive control.** I dropped `protected` from `nowColumnDefault` in
a copy of the head `index.d.ts` (1 hit, then 0). The copy hashes to
`ae5be4b2d6abbda6d50b0c513af286406f61d5d9e9a97a53c8da4d4d0a7b3359`, with
`cmp` exit 1.
- **Export lists.** CJS `require` of each dist gives 59 names (sha1
`05757ce5ae` at both ends); the ESM namespace of `index.mjs` gives the
same 59 at both ends (sha1 `05757ce5ae`). Neither moved function,
neither newly exported declaration and not `SchemaSyncHost` is among
them.
- **The head dist carries the move.** `.call(host` sites in `index.mjs`
go from 67 at base to 69 at head (the two stubs).
### Move-only proof
The proof compares TypeScript compiler AST leaf tokens (JSDoc nodes
skipped), base `4049efa345` against the move commit `fe7fb7ec5`. It is a
scratch script and is not committed.
| Moved body | Body tokens | Comments | Parameter tokens less `this` |
Return type tokens | Body lines |
|:--|--:|--:|--:|--:|--:|
| `nowColumnDefault` | 172 | 31 | 3 | 3 | 51 |
| `applyDeclaredColumnDefault` | 71 | 0 | 11 | 1 | 9 |
- **Each moved body.** In both rows, 0 tokens differ and every comment
is identical. Each body line is the base line less two leading spaces.
Neither is `async` at either end.
- **The two stubs.** Leading trivia (the docblock), modifiers and the
signature are identical to base.
- **The class.** It has 350 members at both ends, in the same order, and
the 348 unmoved members are byte-identical, trivia included.
- **Top level of `sql-driver.ts`.** 175 of 180 base statements are
byte-identical; the other five are the class, the two edited imports
(the spec token import loses `isRuntimeDefaultToken`; the schema-sync
import gains two names and its 2-line comment), and
`MYSQL_DATETIME_PRECISION` and `isNowDefaultValue`, each checked to gain
a leading `export` and nothing else.
- **The module.** Its 45 base statements are all in the head module
byte-identical except three: its first import (whose leading trivia is
the header, which gained the cut 19 paragraph), the
`@objectstack/spec/data` import (`isRuntimeDefaultToken` added) and the
`./sql-driver.js` import (`isNowDefaultValue` and
`MYSQL_DATETIME_PRECISION` added). The head adds the `knex` type import
and the two functions. `SchemaSyncHost` is byte-identical.
- **Result.** `PROOF OK`, exit 0; on the merge head its output is
byte-identical.
- **Negative control.** Through `scripts/ablation-replace.mjs`, I
changed `(cast(utc_timestamp() as date))` to `(cast(utc_timestamp() as
datez))` in the module's `nowColumnDefault` (anchor 1 hit, then 0,
checked on disk). The proof then reports `nowColumnDefault` as
differing, prints `PROOF FAILED`, and exits 1. The restore was proved
(blob `8b345d7a5c` equals HEAD, empty `git diff HEAD`).
### Tests
Each end ran under one `os-verify-lock` hold, after building that end's
driver-sql dist. I compared the vitest JSON per test name and status,
base `4049efa345` against the move commit `fe7fb7ec5`, and then the
merge head `79ca88b71b` against the same base. Every part's exit code
was captured on its own (build, probe, three suites: all 0 at every
leg).
| Suite | Base | Head | Lost / changed / added |
|:--|:--|:--|:--|
| `@objectstack/driver-sql` | 4061 (3847 passed, 214 skipped; 248 files)
| same | 0 / 0 / 0 |
| `@objectstack/driver-turso`, against that end's built driver-sql dist
| 2526 (2492 passed, 34 skipped; 95 files) | same | 0 / 0 / 0 |
| `@objectstack/driver-sqlite-wasm` | 746 (746 passed; 39 files) | same
| 0 / 0 / 0 |
On the merge head (it brings in `main` up to `aa00362fe5`: 12 commits,
none in `packages/drivers/**`), the three suites give the same totals
and the same per-test statuses as base, 0 / 0 / 0 in each. Since then
`main` has moved 11 more commits to `40264beec4`, none in
`packages/drivers/**`; `git merge-tree --write-tree` of the head with it
exits 0, so the tree is not stale.
- **Type check and lint.** `tsc --noEmit -p .` in driver-sql exits 0 on
the move commit and on the merge head. `pnpm exec eslint
--no-inline-config packages/drivers/driver-sql` exits 0 (driver-sql has
no `lint` script of its own).
- **Late-binding probe.** A scratch script, not committed. It runs node
against each end's built dist and prints 149 readings, each with the
result or the error's class, message and top stack frame:
1. `nowColumnDefault` on SQLite, PostgreSQL and MySQL drivers (never
connected) for `date`, `time`, `datetime` and two non-temporal types;
2. a SUBCLASS overriding the `isSqlite` and `isPostgres` getters (the
overrides are the ones read);
3. `knex` replaced on the instance after construction, then restored;
4. `applyDeclaredColumnDefault` on all three dialects over 13
`defaultValue` shapes (absent, `null`, two `NOW()` spellings and a bare
`now`, `current_user` in two cases, an expression envelope, a string,
`0`, `false`, a decimal, an array) for three types, with a recording
column builder, and with no field at all;
5. an instance spy on `nowColumnDefault` (it is the one
`applyDeclaredColumnDefault` reaches);
6. a subclass override of `nowColumnDefault` (likewise);
7. a failure inside the body (`knex` unset): a synchronous `TypeError`;
8. real SQLite DDL through `initObjects`: the stored column defaults
(`PRAGMA table_info`) and a defaulted row's shapes for declared `NOW()`
datetime/date/time fields, literals, `current_user`, `false`, an
option-level `default`, and the audit columns;
9. the SQLite rebuild path (`rebuildSqliteTablePatched`) after a
re-`initObjects` that adds a literal default and a `NOW()` column;
10. both methods' shape on the prototype (type, arity).
- **Probe result.** 148 of the 149 readings are identical. The other one
is reading 7, which differs only in the top stack frame's receiver name:
`_SqlDriver.nowColumnDefault` at base and `Object.nowColumnDefault` at
head. That is shape B's receiver, the same at every earlier cut, and no
test or consumer reads it. On the merge head the probe output is
byte-identical to the move commit's.
- **Not run.** No ablation, because no tested behaviour changed.
- **`test:repo`.** Not run locally; it is CI's run on this PR.
### Gates
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives **48** families for this diff, the
same list on the move commit and on the merge head (and the same 48 cuts
17 and 18 derived). I ran each one on its own and captured its exit code
before any pipe, after a full `pnpm build` of that tree (116 of 116
tasks).
- **Move commit `fe7fb7ec5`: 48 run, all 48 exit 0.** `--ran`
reconciles: `48 derived famil(ies) accounted for — 48 run, 0
NOT-MEASURED`, exit 0. (I fetched the pinned fixture commit of
`check-plugin-teardown-shape.mjs --self-test` into this shallow clone
first.)
- **Merge head `79ca88b71b`: 48 run, all 48 exit 0** (after a second
full `pnpm build`, 116 of 116). `--ran` reconciles the same way, exit 0.
- **Hand gates on both heads, all exit 0:** `check-adr-anchors`,
`check-adr-symbol-anchors`, `check-tenant-audit-census` (244 write call
sites), `check-platform-checklist --changed-from origin/main`,
`check-commit-card-trailers --range origin/main..HEAD`, `eslint
--no-inline-config packages/drivers/driver-sql`,
`check-durability-degradation-log-level --list`. In a clean detached
worktree at base `4049efa345` and on the move commit,
`check-adr-anchors`, `check-adr-symbol-anchors`,
`check-tenant-audit-census` and `check-object-def-param-keys` print
byte-identical output, and `check-durability-degradation-log-level
--list` prints the same seams, line numbers aside.
- **No gate silently empty.** Each derived gate's log prints a non-zero
population (for example `check:object-def-param-keys` compares 7
override parameter positions over 3375 files with every control firing;
`check:tenant-chokepoint` reads 24 `getBuilder()` bindings across 3
files; `check:durability-log-level` reads 48 durability-critical catch
seams and 88 read seams; `check:dual-build-cjs-loads` loads 112 entry
points across 69 packages; `check:driver-conformance` scores 55 covered
cells).
The 48 derived commands: `node
scripts/check-closing-keyword-parity.mjs`, `node
scripts/check-closing-keyword-parity.mjs --self-test`, `node
scripts/check-comment-mask-adoption.mjs`, `node
scripts/check-comment-mask-adoption.mjs --self-test`, `node
scripts/check-comment-mask-corpus.mjs`, `node
scripts/check-dts-emitted.mjs --self-test`, `node
scripts/check-issue-citations.mjs`, `node
scripts/check-plugin-teardown-shape.mjs`, `node
scripts/check-plugin-teardown-shape.mjs --self-test`, `node
scripts/ci/assert-turbo-remote-cache.mjs --self-test`, `node
scripts/ci/plan-test-core-shards.mjs --self-test`, `node
scripts/ci/prune-turbo-cache.mjs --self-test`, `node
scripts/docs-audit/check-affected-docs.mjs`, `node
scripts/docs-audit/check-drift-comment.mjs`, `pnpm --filter
@objectstack/spec run check:duration-unit-keys`, `pnpm
check:ci-filter-parity`, `pnpm check:closed-ceremony-text`, `pnpm
check:cross-package-test-inputs`, `pnpm
check:dispatcher-error-vocabulary`, `pnpm check:doc-authoring`, `pnpm
check:driver-conformance`, `pnpm check:driver-memory-census`, `pnpm
check:dts-closure`, `pnpm check:dual-build-cjs-loads`, `pnpm
check:durability-log-level`, `pnpm check:error-status-conformance`,
`pnpm check:gitlink-declared`, `pnpm check:issue-citations`, `pnpm
check:keyed-text-bounds`, `pnpm check:lean-entry-closure`, `pnpm
check:logger-receiver-detach`, `pnpm check:nul-bytes`, `pnpm
check:object-def-param-keys`, `pnpm check:org-identifier`, `pnpm
check:page-declaration-shape`, `pnpm
check:platform-object-tenancy-census`, `pnpm check:published-files`,
`pnpm check:refd-timer-probe`, `pnpm check:registry-log-declared`, `pnpm
check:rest-log-spy-declared`, `pnpm check:slot-lookup`, `pnpm
check:sourcemap-no-sources-content`, `pnpm check:system-context-census`,
`pnpm check:tenant-chokepoint`, `pnpm check:test-source-alias`, `pnpm
check:tier-file-adoption`, `pnpm check:undeclared-dep-imports`, `pnpm
check:watch-hint-literal`.
## Acceptance notes
- **`check:tenant-chokepoint`'s `SCAN_FILES` does not list
`sql-driver-schema-sync.ts`.** The moved bodies hold 0 of the file's 4
tenant predicates and build no query (they return a `knex.raw` /
`knex.fn.now()` expression or call `defaultTo` on a column builder).
Noted, not filed: widening `SCAN_FILES` would be a gate change.
- **Stale links.** `sql-driver.ts` has the same 30 `{@link X}` sites (21
names) that are neither a top-level binding nor a `SqlDriver` member at
base and at head (the name set is identical). One moved line comment in
`nowColumnDefault` says `{@link canonicalTimeOfDay}`; in the module that
name is not a binding, so the module's own count of such sites goes from
10 to 11. It is a `//` comment, which no tool resolves, and it moved
byte-identical.
- **The series' remaining yield, priced on this base.** After this cut,
two single mechanisms still pay more than -30: date bucketing
(`buildDateBucketExpr`, about -39 with a new module's import) and the
presumed-timestamp update (`updateWithPresumedTimestamp` with
`resolveUpdatedAtColumnPresence`, about -35). Everything else is -28 or
less per mechanism (window function builder -28, `orderKeysFor` -27,
database helpers -27, the four filter-helper mechanisms -29 or less), or
blocked by a series limit (the tenant members).
## Human Minimum
- [x] 1. No `packages/spec` change.
- [x] 2. No new name; `SchemaSyncHost` is unchanged, and two
module-level constants gain `export` (not re-exported by `index.ts`).
- [x] 3. No formatter ran; scoped `eslint --no-inline-config` passes
(repo-wide `pnpm lint` is CI's run).
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. No publishable behaviour change: `skip-changeset`; both
declaration lines above.
- [x] 6. `packages/spec` not touched.
- [x] 7. No hand edits to generated docs, changelogs or release notes.
- [x] 8. Title, body and comments are in English (the maintainer brief
excepted).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FEkQ5m67V6oBcEqg8yLDKL)_
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01FEkQ5m67V6oBcEqg8yLDKL
Co-authored-by: Claude <noreply@anthropic.com>
1 parent a27f889 commit d7f76b6
2 files changed
Lines changed: 107 additions & 66 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
119 | 119 | | |
120 | 120 | | |
121 | 121 | | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
122 | 135 | | |
123 | 136 | | |
124 | 137 | | |
| |||
149 | 162 | | |
150 | 163 | | |
151 | 164 | | |
| 165 | + | |
152 | 166 | | |
153 | 167 | | |
154 | 168 | | |
155 | 169 | | |
156 | 170 | | |
157 | 171 | | |
158 | | - | |
| 172 | + | |
159 | 173 | | |
160 | | - | |
| 174 | + | |
161 | 175 | | |
162 | 176 | | |
163 | 177 | | |
| |||
2064 | 2078 | | |
2065 | 2079 | | |
2066 | 2080 | | |
| 2081 | + | |
| 2082 | + | |
| 2083 | + | |
| 2084 | + | |
| 2085 | + | |
| 2086 | + | |
| 2087 | + | |
| 2088 | + | |
| 2089 | + | |
| 2090 | + | |
| 2091 | + | |
| 2092 | + | |
| 2093 | + | |
| 2094 | + | |
| 2095 | + | |
| 2096 | + | |
| 2097 | + | |
| 2098 | + | |
| 2099 | + | |
| 2100 | + | |
| 2101 | + | |
| 2102 | + | |
| 2103 | + | |
| 2104 | + | |
| 2105 | + | |
| 2106 | + | |
| 2107 | + | |
| 2108 | + | |
| 2109 | + | |
| 2110 | + | |
| 2111 | + | |
| 2112 | + | |
| 2113 | + | |
| 2114 | + | |
| 2115 | + | |
| 2116 | + | |
| 2117 | + | |
| 2118 | + | |
| 2119 | + | |
| 2120 | + | |
| 2121 | + | |
| 2122 | + | |
| 2123 | + | |
| 2124 | + | |
| 2125 | + | |
| 2126 | + | |
| 2127 | + | |
| 2128 | + | |
| 2129 | + | |
| 2130 | + | |
| 2131 | + | |
| 2132 | + | |
| 2133 | + | |
| 2134 | + | |
| 2135 | + | |
| 2136 | + | |
| 2137 | + | |
| 2138 | + | |
| 2139 | + | |
| 2140 | + | |
| 2141 | + | |
| 2142 | + | |
| 2143 | + | |
| 2144 | + | |
| 2145 | + | |
| 2146 | + | |
| 2147 | + | |
| 2148 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
58 | | - | |
| 58 | + | |
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
| |||
168 | 168 | | |
169 | 169 | | |
170 | 170 | | |
171 | | - | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
172 | 174 | | |
173 | 175 | | |
174 | 176 | | |
| |||
482 | 484 | | |
483 | 485 | | |
484 | 486 | | |
485 | | - | |
| 487 | + | |
486 | 488 | | |
487 | 489 | | |
488 | 490 | | |
| |||
572 | 574 | | |
573 | 575 | | |
574 | 576 | | |
575 | | - | |
| 577 | + | |
576 | 578 | | |
577 | 579 | | |
578 | 580 | | |
| |||
15474 | 15476 | | |
15475 | 15477 | | |
15476 | 15478 | | |
15477 | | - | |
15478 | | - | |
15479 | | - | |
15480 | | - | |
15481 | | - | |
15482 | | - | |
15483 | | - | |
15484 | | - | |
15485 | | - | |
15486 | | - | |
15487 | | - | |
15488 | | - | |
15489 | | - | |
15490 | | - | |
15491 | | - | |
15492 | | - | |
15493 | | - | |
15494 | | - | |
15495 | | - | |
15496 | | - | |
15497 | | - | |
15498 | | - | |
15499 | | - | |
15500 | | - | |
15501 | | - | |
15502 | | - | |
15503 | | - | |
15504 | | - | |
15505 | | - | |
15506 | | - | |
15507 | | - | |
15508 | | - | |
15509 | | - | |
15510 | | - | |
15511 | | - | |
15512 | | - | |
15513 | | - | |
15514 | | - | |
15515 | | - | |
15516 | | - | |
15517 | | - | |
15518 | | - | |
15519 | | - | |
15520 | | - | |
15521 | | - | |
15522 | | - | |
15523 | | - | |
15524 | | - | |
15525 | | - | |
15526 | | - | |
15527 | | - | |
| 15479 | + | |
| 15480 | + | |
| 15481 | + | |
| 15482 | + | |
| 15483 | + | |
| 15484 | + | |
| 15485 | + | |
| 15486 | + | |
| 15487 | + | |
| 15488 | + | |
| 15489 | + | |
| 15490 | + | |
15528 | 15491 | | |
15529 | 15492 | | |
15530 | 15493 | | |
| |||
17380 | 17343 | | |
17381 | 17344 | | |
17382 | 17345 | | |
17383 | | - | |
17384 | | - | |
17385 | | - | |
17386 | | - | |
17387 | | - | |
17388 | | - | |
17389 | | - | |
17390 | | - | |
17391 | | - | |
| 17346 | + | |
| 17347 | + | |
| 17348 | + | |
| 17349 | + | |
| 17350 | + | |
17392 | 17351 | | |
17393 | 17352 | | |
17394 | 17353 | | |
| |||
0 commit comments