Skip to content

refactor(driver-sql): codemod pilot — generated, byte-identity-proved section split of sql-driver.ts (#29520) - #29598

Merged
os-zhuang merged 27 commits into
mainfrom
claude/issue-29520-sql-driver-codemod-pilot
Nov 3, 2026
Merged

os-zhuang merged 27 commits into
mainfrom
claude/issue-29520-sql-driver-codemod-pilot

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Requested by 田騏 · project thread

Fixes #29520

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:codemod scripts/codemod-split-sql-driver.mjs 生成的 sql-driver.ts 拆分。54 个方法体移入 18 个分节模块,127/129 个类外顶层声明移入叶模块 sql-driver-top-level.ts。check-tenant-chokepoint 扫描全部非测试 sql-driver-*.ts,其 dispatch-gates 声明补上 main 新增的 sql-driver-balanced-group.ts,自测失败时直接写出要加或删的条目。按裁决 6597555122 第 3 点,按路径读取 sql-driver.ts 的读者跟随代码扩到新模块:sql-driver-compile-refusal-seam.test.ts 的 sources 加入叶模块,logger-receiver-detach.test.ts 的 pin ③ 改为列目录读全部 sql-driver*.ts,liveness 台账的一条锚点改指叶模块,ADR-0053 锚点登记为三个新模块各加一条。根 package.json 加入 devDependency ts-morph ^28.0.0(fix(deps): a fresh scaffold's tree carries no ts-morph — the CLI takes the compiler from typescript directly #29711 后已无包声明它),codemod 从根清单解析。生成文件未手改。
  • 为什么改:落实 Codemod split pilot: generate the sql-driver.ts split with a deterministic script, verified byte-identical #29520 第三轮(裁决 6597555122 选项 A)。测试读取清单加入叶模块后,sql-driver.ts 从 18,334 行降到 12,460 行,低于 13,000 行的门槛。
  • 风险与回滚:纯搬移。54/54 方法体、127/127 顶层声明逐字节相同;撤销拆分可逐字节还原 base;三套驱动测试计数与 base 相同(driver-sql 多 1 条,是 pin ③ 新增的下限用例);门禁读数 base = head。打包 .d.ts 按 6441032442 B 的第二归一化判通过,四项读数全部相等,阳性对照抓到去掉的 private。回滚即 revert。
  • 先看:① 下方「按路径读取 sql-driver.ts 的读者」表(哪些读者跟随了代码);② scripts/codemod-split-sql-driver.mjs 的 CLASS_PATH_READER_NEEDLES;③ .d.ts 读数表。
  • 两分钟验证:pnpm install --frozen-lockfile 后运行 node scripts/codemod-split-sql-driver.mjs --verify --base 0b5b176038,预期 54/54 moved bodies identical、127/127 moved top-level declarations identical、18334 -> 12460 lines,退出码 0。
  • 需要你做的:无新裁决。超过 3,000 行,按四件套交接,待您批准后在您定的窗口落地;本 PR 保持草稿。

What changes

  • scripts/codemod-split-sql-driver.mjs (round 3): the three seam-test needles move from PATH_READER_NEEDLES into a new CLASS_PATH_READER_NEEDLES table: unsupportedFilterError(, withheldFilterError( and .INVALID_FILTER.
    • The reader of these needles now reads the leaf, so a top-level declaration carrying one moves to it. That frees the 29 refusal builders and the 6 declarations that close over them.
    • A method carrying one still stays on the class. The test reads no section module, and it pins SqlDriver.resolveWithheldFilterRefusal by name.
    • Measured: dropping the three needles outright moves that method too (55 methods, 12,449 lines), and the test's enumeration would then go red.
    • A stale class needle refuses, as a stale needle does.
    • Two mutants are each refused with 2 failures: the method rule removed, and the class needles applied to top-level declarations.
    • Review fixes: --help / -h is answered before any guard (it was refused on a split tree), and --dts counts a line-count change as diff does (it read 0), naming the count in rawDiffMethod.
    • --self-test: 45 cases in 5 pinned batteries. A mutant of each review fix is refused.
  • Root package.json and pnpm-lock.yaml: ts-morph ^28.0.0 joins the root devDependencies, beside typescript, yaml and semver. The codemod now resolves it from the root manifest.
    • Why: fix(deps): a fresh scaffold's tree carries no ts-morph — the CLI takes the compiler from typescript directly #29711 removed ts-morph from @objectstack/cli, and no workspace package declares it. The codemod resolved it through the CLI, so on a fresh pnpm install --frozen-lockfile its --verify and --self-test exited 2.
    • The lockfile was written by pnpm install --lockfile-only (+25 lines, nothing else re-resolved). It adds ts-morph@28.0.0, @ts-morph/common@0.29.0 and code-block-writer@13.0.3. @ts-morph/common's minimatch resolves to the 10.2.6 already in the tree, under the existing minimatch@<11.0.0 override.
    • Proved from clean: every node_modules removed, then pnpm install --frozen-lockfile. With only ts-morph set aside, the script exits 2 and names the root manifest.
  • scripts/check-tenant-chokepoint.mjs: DECLARED_WATCH_HINTS gains sql-driver-balanced-group.ts, which fix(driver-sql): emit large $or / $and groups as balanced halves so gated comment and attachment reads fit hosted libSQL's depth limit #29911 added on main. The scan lists the directory, so it already read the module. The self-test's coupling asserts now name each missing or extra entry, and the one edit that fixes it.
    • Why the list stays literal: the dispatch-gates extractor does accept packages/drivers/driver-sql/src/sql-driver-*.ts and judges it as a pattern. Through hintCovers, though, it covers 31 seam modules and 234 sql-driver-*.test.ts files, plus any .d.ts. A hint has no negation, and ? and […] are not admitted, so no spelling covers the modules and leaves the tests out. The gate's docblock records this.
    • Before the literal was added, the self-test failed with: Fix: add 'packages/drivers/driver-sql/src/sql-driver-balanced-group.ts' to DECLARED_WATCH_HINTS in this gate.
  • sql-driver-compile-refusal-seam.test.ts: sources gains sql-driver-top-level.ts under a [#29520 codemod] comment, in the same form as hand cuts 13, 15 and 16. The enumeration prose names the leaf too.
  • logger-receiver-detach.test.ts pin ③: it read sql-driver.ts only and asserts an absence, so it stayed green while 3 of the host's 21 log-channel calls moved out. It now lists its directory and reads every non-test sql-driver*.ts (a named list would rot at the next regeneration), with a floor case that the listing finds more than the host. It reads 55 calls at base and at head. Ablation: a planted (this.logger.error ?? this.logger.warn)( in sql-driver-internal-helpers.ts turns it red; the old host-only pin stays green on the same tree.
  • packages/spec/liveness/query.json: the one anchor whose symbol moved, unsupportedAggregationFilterError, now cites sql-driver-top-level.ts. Nothing else in the ledger changes; the other nine driver-sql anchors still resolve in sql-driver.ts.
  • scripts/adr-anchors/: three new ADR-0053 entries, for sql-driver-sqlite-serialisation.ts (formatOutput's folds), sql-driver-filter-helpers.ts (presentReadValue's datetime and audit arms) and sql-driver-top-level.ts (the fold helpers), in the shape [maintainer] refactor(driver-sql): split src/sql-driver.ts (22,096 lines, +2,533 in 30 days) along its SqlDriver seams, one move-only slice per PR #25521 cut 8 gave sql-driver-schema-sync.ts. 18 of the host's 33 ADR-0053 citations moved with that code; the host entry stays for the stubs and the 15 left. Removing ADR-0053 from one module turns check:adr-anchors red.
  • Unchanged from round 2:
    • lever (a): section modules may import values from sql-driver.ts. This round it exports no staying helper, because every helper the moved bodies read now sits in the leaf;
    • lever (b): one leaf that never imports back;
    • the stub host's bound getBuilder;
    • the widened check-tenant-chokepoint;
    • the no-yield rule;
    • no re-indentation.
  • The generated split: --write on origin/main, unedited. On the latest merge base 0b5b176038, fix(driver-sql): emit large $or / $and groups as balanced halves so gated comment and attachment reads fit hosted libSQL's depth limit #29911 changed sql-driver.ts (input sha256 2d2ebebdba87…). The resolution took main's packages/drivers/driver-sql/src and kept this branch's two test files, then regenerated. The same 54 methods and 127 declarations move, and the result differs from the previous head only by fix(driver-sql): emit large $or / $and groups as balanced halves so gated comment and attachment reads fit hosted libSQL's depth limit #29911's own change. It produces sql-driver.ts, the leaf, and 18 section modules:
    • lifecycle, crud, sequence-semantics, bulk-operations, aggregation, distinct;
    • window-functions, query-plan, schema-sync-section, rotation, managed-drift, internal-helpers;
    • filter-helpers, field-mapping, window-function-builder, column-creation, database-helpers, sqlite-serialisation.

Measurements

Reading Value
sql-driver.ts lines (wc -l) 18,334 → 12,460 (−5,874). Bar: below 13,000. Met
Methods 54 of 254 move (2,596 body lines out, 616 stub lines in, 36 import lines)
Top-level declarations 127 of 129 move (3,784 lines with their docblocks). 2 stay, both path-reader: JSON_COLUMN_TYPES and MEDIA_ID_VARCHAR_CHARS, which the cli pins read
Leaf / new files sql-driver-top-level.ts 3,999 lines; all 19 new files 9,575 lines
Byte-identity 54/54 bodies, 127/127 top-level declarations identical; undoing the split rebuilds the base byte-for-byte
Determinism output tree sha256 088547bdc1b4e152d6298d4a1d33b007eec27871e179716a298944b673984170 on three runs: --write in the worktree and two plan runs on main's unsplit text. Input sha256 2d2ebebdba87…
Chokepoint readings base (main, widened gate): 24 getBuilder() bindings, 21 read doors, 3 inserts, 4 tenant predicates, 0 D8 arms across 15 files. Head: identical across 34 files
Export lists .d.ts 92 = 92; runtime CJS 59 = 59 and ESM 59 = 59 (CJS = ESM)
Changed lines 17,073 (+10,528 / −6,545, 30 files)

Readers of sql-driver.ts by path (ruling 6597555122 point 3)

Reader Asserts Host matches moved Now
seam test enumeration exact set 26 / 28 reads the leaf
logger-receiver-detach pin ③ absence 3 / 21 reads every sql-driver*.ts
check-tenant-chokepoint absence + floors 18 / 24 reads 34 files (round 2)
liveness #anchor citations presence 1 / 14 re-pointed
ADR-0053 anchor registry presence anywhere in file 18 / 33 3 new entries
5 cli pins, check-keyed-text-bounds presence (slices) 0 held by needles / pins
check-durability-degradation-log-level absence (same-file helper) 2 / 9 (to sql-driver-column-creation.ts:53 and :84; the host still counts 9 because two new stubs forward) repo-wide scan, green
ADR / QA #symbol anchors, check-object-def-param-keys, cli test cache inputs presence 0 unchanged

.d.ts: ruling 6441032442 item 1, second normalisation, with ruling 6597555122's header clarification

The normaliser is dtsnorm.mjs, sha256 9e3ca459fb22015c7e77e4576b564ca46076cfd0f366dc00dcec521274f8e911. The devx lane rewrote it from the ruling's text. It is a report reading, ⛔ not in scripts/ (item 3). It does three things:

  • It splits each file into top-level statements with the TypeScript API. Each statement keeps its attached comments byte for byte.
  • A leading comment separated by a blank line is a detached file-level comment. It leaves the statement stream and is compared on its own as a multiset, so its text still must not change.
  • It sorts the statements and the specifier lists inside import { } / export { }, and masks chunk hashes. driver-sql emits no chunk.

Base is main 0b5b176038's unsplit src, built. Head is 5f30cf9f2c, built. The readings are the same as round 3's, hash for hash. Each reading below is the same for index.d.ts and index.d.mts.

Reading Base Head Verdict
Raw sha256 0f33bf3f… 69d9162d… differ; raw diff 19 lines, wc -l 8,846 → 8,847
Normalised bytes 468260520fcc1ac2… 468260520fcc1ac2… identical
Declared-surface digest (100 declarations, 585 lines) 50e5e5be3c1d… 50e5e5be3c1d… equal
Statement multiset 106 106 equal: only in base 0, only in head 0. Before the specifier sort it is 2 / 2, the two @objectstack/spec imports
Export set 92 92 equal; import specifier set 17 = 17
Detached comments 2 2 equal texts. The "SQL Driver for ObjectStack" header now sits before declare class SqlDriver, which ruling 6597555122 does not count

Positive control (catches a dropped private). I dropped private from one moved member's stub, compileFilters, rebuilt, ran the normaliser on head against control, then restored and rebuilt. The rebuilt head .d.ts is byte-identical to the earlier head. The control is caught on three readings:

  • normalised hashes differ: 468260520fcc… vs 73e89389695f…;
  • surface digests differ: 50e5e5be3c1d… vs acf70f0378d0…. It names PropertyDeclaration [private] compileFilters → MethodDeclaration [] compileFilters;
  • the statement multiset is 1 / 1.

The normaliser exits 1 on both files. Its --self-test passes 8 cases, among them a member reordered inside its class and a changed header text, both refused.

Premises.

  • P2: driver-sql exports is . only. It names dist/index.* and no chunk.
  • P3: git grep 'driver-sql/dist' -- scripts package.json finds 0 hits.
  • (e) Dependents are green against the head dist: the driver-turso and driver-sqlite-wasm typecheck and suites ran after the head build.
Why most methods stay (counted per method; one method can carry several)

already-moved 78 · no-yield 55 · non-public-static 47 · parameter-shape 21 · this-write 19 · path-reader 18 · no-section 14 · static 11 · comment-in-parameters 7 · field-call 6 · inferred-return-type 6 · type-parameters 3 · name-taken 3 · reserved-name 1. The full table is the script's plan output.

Tests

Every run below is at head 5f30cf9f2c on merge base 0b5b176038, after every node_modules was removed and pnpm install --frozen-lockfile re-ran. Each ran under one os-verify-lock hold (VERDICT command-exit 0). The base runs used main's unsplit src, built and then restored in place; status was clean afterwards.

  • Type-check: driver-sql, driver-turso and driver-sqlite-wasm each exit 0.
  • @objectstack/driver-sql test: exit 0 at both. 250 files (238 passed, 12 skipped). Base 4074 tests (3858 passed, 216 skipped); head 4075 (3859 passed, 216 skipped): the +1 is pin ③'s new floor case.
  • @objectstack/driver-turso test: exit 0 at both. 96 files; 2530 tests (2496 passed, 34 skipped). Base = head.
  • @objectstack/driver-sqlite-wasm test: exit 0 at both. 40 files; 750 tests passed. Base = head.
  • The five packages/cli pin tests that read sql-driver.ts by path exit 0:
    • unit: 4 files, 62 tests;
    • integration (generate-string-family-width): 1 file, 30 tests.
  • sql-driver-compile-refusal-seam.test.ts: 115/115. With the new sources line removed, 3 tests fail (the ablation above).
  • logger-receiver-detach.test.ts: 12/12; the planted shape fails it (ablation above).
  • packages/spec check-liveness.test.ts 74/74 and check:liveness exit 0.
  • Codemod: --self-test 45 cases in 5 batteries; --verify --base 0b5b176038 exits 0 (54/54, 127/127, 12,460 lines); two plan runs on base's unsplit text give tree 088547bd… both times, byte-identical; --help on the split tree exits 0.
  • check-tenant-chokepoint --self-test and main run exit 0. check:adr-anchors and check:adr-symbol-anchors exit 0.

Acceptance notes

  1. The bar is met: 12,460 lines. Round 3 measured 12,456 on the older base; fix(driver-sql): emit large $or / $and groups as balanced halves so gated comment and attachment reads fit hosted libSQL's depth limit #29911 added 4 lines to code that stays on the class.
  2. The three needles still bind methods. That is what keeps the test green (see What changes). Literally deleting them would move resolveWithheldFilterRefusal into sql-driver-filter-helpers.ts, which the test does not read.
  3. .d.ts passes ruling 6441032442 B's second normalisation on all four readings, with the control caught. Ruling 6348891160's union-order bar alone still reads FAIL on these files. Under 6441032442 item 1, that is the case the second normalisation exists for.
  4. Full pnpm build exits 2 in @object-ui/app-shell (Cannot find module '@object-ui/mobile'), outside this change. Every driver and cli closure used here builds.
  5. Size. 17,073 changed lines is over the 3,000 threshold. Per ruling 6597555122 the PR takes the four-piece hand-off and a maintainer approval, and lands in the window the maintainer sets. It stays a draft.
  6. skip-changeset: the .d.ts meets item 1 by ruling 6441032442, so per item 4 it takes no changeset.

Verification

  • Byte-identity: pnpm install --frozen-lockfile, then node scripts/codemod-split-sql-driver.mjs --verify --base 0b5b176038.
  • .d.ts: build @objectstack/driver-sql at main's unsplit src and at head. Then run node dtsnorm.mjs --diff BASE/index.d.ts HEAD/index.d.ts, and the same for .d.mts. Expect exit 0 and "pass": true. The Codemod split pilot: generate the sql-driver.ts split with a deterministic script, verified byte-identical #29520 report gives the normaliser's path and sha256.
  • Chokepoint: node scripts/check-tenant-chokepoint.mjs prints the readings line.
  • Re-running in the landing window: merge the latest main and take main's packages/drivers/driver-sql/src, keeping this branch's sql-driver-compile-refusal-seam.test.ts and logger-receiver-detach.test.ts. Then run --write and commit. If a regeneration moves different code, re-check the reader table above.
Gates at head 5f30cf9
  • node scripts/pm/dispatch-gates.mjs --commands derives 92 families at 5f30cf9f2c on merge base 0b5b176038, the same list as at 5b19e9ac05. Each was run alone after the fresh install, with its exit captured before any pipe: 92 exit 0, check:tenant-chokepoint among them.
  • The --ran reconciliation reads 92 derived, 92 run, 0 NOT-MEASURED, 0 UNRUN, exit 0.
  • Not measured here: the OSV-Scanner job. CI runs it base-relative because the lockfile changed, and the local proxy refuses api.osv.dev. The only advisory-bearing package the three lockfile additions reach is minimatch 10.2.6, which is already in the merge base's lockfile and already covered by the GHSA-g3hv-75wg-m249 exemption.
  • Also run: the codemod's --dts (ruling 6348891160's bar alone reads FAIL, as before), the seam and logger tests together (127/127), and spec check:liveness.
  • check:commit-card-trailers passed on every push.

Durable attribution: session session_017ihL2gLghEqeDKTbDTC7Zd (domain:devx#2, os-dev).

🤖 Generated with Claude Code

https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd

…er.ts and proves the move

A deterministic ts-morph codemod: per section banner of SqlDriver, the
bodies of every method that can move under the hand series' cut pattern go
to sql-driver-<section>.ts unedited, the class keeps one-line host stubs, and
the script proves byte-identity (undoing the split rebuilds the base file
byte-for-byte) and, on two built dists, the declaration-file bar of ruling
6348891160 item 1. ts-morph resolves through packages/cli's closure; the
root adds no dependency.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…emod-split-sql-driver.mjs

Output of `node scripts/codemod-split-sql-driver.mjs --write` on
sql-driver.ts at dbca3ef, unedited: 20 method bodies in 10 sections move
to section modules, the class keeps host stubs. Byte-identity proved by the
script (undoing the split rebuilds the base file byte-for-byte).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…ed parse

check:parse-guard flagged the raw createSourceFile: a parse whose errors
nobody read. The text now passes parseSourceFile first, which refuses a
source with parse errors, and ts-morph reads the vouched-for text.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/driver-sql, @objectstack/spec, touching 447 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/spec/liveness/query.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

90 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 40a35ded4157eb685e09a31672abc3f959ec9d5f.

⛔ 15 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/liveness/query.json) — pages documenting those are invisible to this run
  • 2 anchor(s) matched too much of the corpus to be a work list: created_at (literal, 43 pages), organization_id (literal, 38 pages)
  • 19 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 103 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 170 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 40a35ded4157eb685e09a31672abc3f959ec9d5f → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 3c556753325153fa135761aa4db663b192cedd6f — the merge of head 5f30cf9f2cb4725398af42ea3876f9e246715afc into base 40a35ded4157eb685e09a31672abc3f959ec9d5f, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 3c556753325153fa135761aa4db663b192cedd6f && git checkout 3c556753325153fa135761aa4db663b192cedd6f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 40a35ded4157eb685e09a31672abc3f959ec9d5f 5f30cf9f2cb4725398af42ea3876f9e246715afc && git checkout -B drift-repro 40a35ded4157eb685e09a31672abc3f959ec9d5f && git merge --no-ff 5f30cf9f2cb4725398af42ea3876f9e246715afc

node scripts/docs-audit/affected-docs.mjs --json 40a35ded4157eb685e09a31672abc3f959ec9d5f

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 40a35ded4157eb685e09a31672abc3f959ec9d5f → pass the list as
args.docs, on the commit named under Which tree this was computed on.

claude added 11 commits November 3, 2026 00:09
…ttern

Lever (a): a section module imports values from sql-driver.ts; a staying
top-level name a moved body reads is exported by one generated export list.
Lever (b): the top-level declarations ahead of the class move whole, with
their comments, into the leaf sql-driver-top-level.ts, which never imports
sql-driver.ts or a seam module; sql-driver.ts imports back what it reads and
re-exports by name what it exported. The tenant-chokepoint stay rule goes
(the gate now reads the seam modules); the host hands getBuilder as a bound
reference. Path readers are kept whole by PATH_READER_PINS and the new
PATH_READER_NEEDLES. The byte-identity proof splices the leaf back by name
and rebuilds the base byte-for-byte.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…dened cut pattern

Output of `node scripts/codemod-split-sql-driver.mjs --write` on
sql-driver.ts at origin/main b391feb (input sha256 e73b1ce952e1), unedited:
56 method bodies move to 18 section modules, 97 of the 130 top-level
declarations ahead of the class move to sql-driver-top-level.ts, and
sql-driver.ts goes from 18333 to 13971 lines. Byte-identity proved by the
script; output tree sha256 bee30883147c, the same on two runs.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…am module

SCAN_FILES widens to the non-test sql-driver-*.ts modules of driver-sql/src,
listed from the directory (ruling 6591753301), and a module-level function is
read as a class member is, under its own name, so a moved body is still a
door. The gate prints its readings (bindings, read doors, tenant predicates,
D8 arms) on one line. The watch hints declare each seam module by name; the
self-test holds them to the listing both ways and gains a moved-bodies
battery.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…s carries none of it

The bundler keeps a JSDoc block that leads a module's first statement, and
the leaf is bundled first, so its /** */ header was published as 14 lines
the base dist/index.d.ts did not carry. The header is // lines now; the
self-test holds that.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
Output of `node scripts/codemod-split-sql-driver.mjs --write` on
sql-driver.ts at origin/main b391feb (input sha256 e73b1ce952e1),
unedited. Only sql-driver-top-level.ts's header changes; output tree sha256
5187eba96f64, the same on two runs.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
… gate resolves their log helper

check-durability-degradation-log-level follows same-file helpers, so a moved
catch whose only log is this.logDurabilityFailure(...) read as swallowed
(measured: migrateMysqlDatetimeColumns and migrateMysqlTimeColumns red).
PATH_READER_NEEDLES gains this.runWideningAlters( with that reader.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
Output of `node scripts/codemod-split-sql-driver.mjs --write` on
sql-driver.ts at origin/main b391feb (input sha256 e73b1ce952e1),
unedited: 54 method bodies and 97 top-level declarations move;
sql-driver.ts 18333 -> 14042 lines. Output tree sha256 f4dc8078d9b7, the
same on two runs.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
A SEAM_DIR constant read to bare-root-worklist as a new invisible bare-root
population; the gate already declares every file it reads, one by one, in
DECLARED_WATCH_HINTS, so the directory is spelled inline as the three
driver files are.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…l-driver-codemod-pilot

# Conflicts:
#	packages/drivers/driver-sql/src/sql-driver.ts
Output of `node scripts/codemod-split-sql-driver.mjs --write` on
sql-driver.ts at origin/main 2ea6042 (input sha256 9abf7867fd98; #29660
touched it), unedited: 54 method bodies move to 18 section modules and 96 of
the 129 top-level declarations ahead of the class to sql-driver-top-level.ts;
sql-driver.ts 18330 -> 14050 lines. Output tree sha256 ab8990700a0d, the
same on two runs.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd

Seat park note · 2026-11-03T06:18Z · parked under landing-operations.md §C

…d methods only

Ruling 6597555122 (round 3): sql-driver-compile-refusal-seam.test.ts adds
sql-driver-top-level.ts to the sources it enumerates, in the form of hand
cuts 13, 15 and 16. Its three needles leave PATH_READER_NEEDLES for a new
CLASS_PATH_READER_NEEDLES table. A top-level declaration carrying one now
moves to the leaf the test reads. A method carrying one still stays on the
class, because its body would land in a section module the test does not
read and drop SqlDriver.resolveWithheldFilterRefusal out of the pinned set.
A stale class needle refuses, as a stale needle does. The self-test has 43
cases.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
… the leaf

The output of node scripts/codemod-split-sql-driver.mjs --write on
origin/main 7a25b39's unsplit sql-driver.ts, unedited. 127 of 129
top-level declarations now move to sql-driver-top-level.ts (96 before), and
54 of 254 methods move as before. sql-driver.ts goes 18,330 -> 12,456 lines.
--verify: 54/54 bodies and 127/127 declarations are byte-identical to the
base, and undoing the split rebuilds the base byte-for-byte. The output tree
sha256 is f5d8722fa697b4530b9f76922c2b5d579f69048463e09cf190693793400b26e0.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
@github-actions github-actions Bot added the tests label Nov 3, 2026
…terError to the leaf

The #29520 codemod moved the top-level declaration unsupportedAggregationFilterError
from sql-driver.ts to the generated leaf sql-driver-top-level.ts. That left the
query/aggregations.filter evidence anchor naming a symbol the cited file no
longer has, which turned check-liveness.test.ts red in CI. Ruling 6597555122
point 3 says a reader that cites a file by path gains the new module in the same
PR, so the one citation now names the leaf. Nothing else in the ledger changes.
The other nine driver-sql anchors still name a symbol sql-driver.ts declares.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…t of sql-driver.ts

Ruling 6597555122 point 3. Pin 3 of logger-receiver-detach.test.ts asserted
that no detach-then-call shape survives in sql-driver.ts, and read only that
file. The #29520 split moved 3 of the host's 21 log-channel calls into
sql-driver-internal-helpers.ts, sql-driver-filter-helpers.ts and
sql-driver-field-mapping.ts. Because the pin asserts an absence, it stayed
green while it read less.

The pin now lists the directory and reads every non-test sql-driver*.ts. A
named list would rot whenever the codemod is regenerated on a newer main and
moves a different set. A floor case fails if the listing finds nothing past
the host. At base and at head the pin reads 55 log-channel calls (44 warn).
Planting (this.logger.error ?? this.logger.warn)( in
sql-driver-internal-helpers.ts turns it red. The old host-only pin stays
green on that same planted tree.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…line-count change

Two defects the #29520 review found.

--help was refused by the "already carries stubs" guard (exit 2) on any split
tree. It is now answered before any guard and prints the usage.

dtsBarFor reported rawDiffLines 0 whenever the two declaration files had
different line counts. It now counts what diff prints (lines deleted plus
inserted, a Myers edit distance) and names the method in rawDiffMethod. On
round 3's dists it reads 19, the same as diff. When the counts are equal it
still counts lines that differ in place, one per union swap.

The self-test has 45 cases. A mutant of each fix is refused.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…s into their modules

Ruling 6597555122 point 3, applied to the anchor registry. The #29520 split
moved the code the sql-driver.ts ADR-0053 entry names out of that file:
formatOutput's folds went to sql-driver-sqlite-serialisation.ts,
presentReadValue's datetime and audit arms to sql-driver-filter-helpers.ts,
and the fold helpers to sql-driver-top-level.ts. 18 of the host's 33
ADR-0053 citations left with them. check:adr-anchors stayed green on the
15 left behind while it guarded less.

Each of the three modules now has its own ADR-0053 entry. Each entry's
invariant names the code that moved there, in the shape #25521 cut 8 gave
sql-driver-schema-sync.ts. The host entry stays: the stubs still live
there, and so do 15 citations. Removing ADR-0053 from one module turns
the gate red.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…Dependency

#29711 dropped ts-morph from @objectstack/cli, and no workspace package
declares it any more. The codemod resolved ts-morph through the CLI's
closure, so on a fresh `pnpm install --frozen-lockfile` its --verify and
--self-test stopped at exit 2 and the ruled proofs could not be reproduced
from a clean checkout.

- package.json: ts-morph ^28.0.0 joins the root devDependencies, the way
  the other root scripts take typescript, yaml and semver.
- pnpm-lock.yaml: written by `pnpm install --lockfile-only`. It adds
  ts-morph@28.0.0, @ts-morph/common@0.29.0 and code-block-writer@13.0.3.
  @ts-morph/common's minimatch resolves to the 10.2.6 already in the tree.
- scripts/codemod-split-sql-driver.mjs: the loader resolves from the root
  manifest. The header says so, and also says which exit a tree with no
  install at all gets.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Nov 3, 2026
…l-driver-codemod-pilot

#29911 changed sql-driver.ts. The resolution takes main's
packages/drivers/driver-sql/src whole, keeps this branch's
sql-driver-compile-refusal-seam.test.ts and logger-receiver-detach.test.ts,
and regenerates the split with `node scripts/codemod-split-sql-driver.mjs
--write`, unedited.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
…oup.ts and names the fix when a module is undeclared

The gate lists every non-test sql-driver-*.ts module from its directory.
Its dispatch-gates declaration is a literal list. #29911 added
sql-driver-balanced-group.ts, and the self-test went red with a message that
did not say what to change.

- DECLARED_WATCH_HINTS gains sql-driver-balanced-group.ts.
- Both coupling asserts now name each missing or extra entry, and say to
  add it to or remove it from DECLARED_WATCH_HINTS.
- The docblock records why the list stays literal. The extractor accepts
  a sql-driver-*.ts glob, but through hintCovers that glob covers 31 seam
  modules and 234 test files. A hint has no negation, so no spelling covers
  the modules and leaves the tests out.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2gLghEqeDKTbDTC7Zd
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd

席位核对 — ACCEPT · domain:devx#2 · head 5f30cf9f2cb4725398af42ea3876f9e246715afc · 2026-11-03T13:55Z

Checked against GitHub, the PR head, two independent full reviews (Fable) and the dev's addenda on #29520 (6598599265, 6598841687, 6600292358, 6601642667, 6603121383, 6605104686).

  • Shape: a draft to main with Fixes #29520. 17,073 changed lines over 30 files, so check-governed-merges --pr 29598 reads HUMAN MERGE OR AUTHORIZED APPROVAL. check-expected-skips reads OK (11 skipped, each in main's roster). CI on this head is green: 58 success, 11 skipped, 0 failed.
  • The rulings, against the head:
    • Ruling A (6591753301) and its round-2 answer (6597555122) are met. The codemod regenerates sql-driver.ts from 18,334 to 12,460 lines on merge base 0b5b176038, under the 13,000 bar. The seam test reads the leaf, as cuts 13, 15 and 16 do.
    • --verify byte-identity passes: 54/54 method bodies and 127/127 top-level declarations, and undoing the split rebuilds the base byte for byte. The output tree is deterministic.
    • The .d.ts is judged by 6441032442 B. All four readings are equal (normalised bytes, surface digest, statement multiset 106 = 106, export set 92 = 92), and the positive control catches a dropped private.
    • Chokepoint readings are equal at base and head (24 / 21 / 3 / 4 / 0).
    • The driver suites are at base counts, plus pin ③'s floor case.
  • Every reader of sql-driver.ts by path, under ruling point 3:
  • Independent review: two full Fable reviews. The first found the unwidened pin ③; the second found ts-morph unresolvable from a clean tree. Both are fixed and re-proved from a fresh install. The packages/spec change passed review with no finding.
  • Accepted deviations:
    1. ts-morph ^28.0.0 becomes a root devDependency (+25 lockfile lines). fix(deps): a fresh scaffold's tree carries no ts-morph — the CLI takes the compiler from typescript directly #29711 had removed it from the CLI, which left the codemod unrunnable from a clean checkout.
    2. Three needles moved into a method-only CLASS_PATH_READER_NEEDLES table, so resolveWithheldFilterRefusal stays where the seam test pins it.
    3. The minimatch-parent prose in osv-scanner.toml and pnpm-workspace.yaml is not edited here. By the ledger's convention, an exemption text change goes in its own PR.
  • Not measured: OSV-Scanner locally, because the proxy refuses api.osv.dev. CI runs it base-relative.
  • Out of scope, for the engine.ts / protocol.ts / registry.ts cards: the codemod's path-reader scan should also learn liveness and ADR #anchor citations, and absence-asserting readers. The dev measured engine.ts at 5 top-level anchors at risk and registry.ts at 2. Skills-docs: none — internal refactor.
  • Landing: governed hand-off ③. The seat sets itself as the PR's assignee (docs(agents): one home for who sets a PR's assignee — the seat at hand-over, never the dev's pr_create #29832), marks the PR ready, requests review from os-zhuang and hotlong, and adds needs-user-decision. The merge lands in the window the maintainer sets.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 3, 2026 13:56
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit d46b1ff Nov 3, 2026
75 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-29520-sql-driver-codemod-pilot branch November 3, 2026 16:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file needs-user-decision size/xl skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codemod split pilot: generate the sql-driver.ts split with a deterministic script, verified byte-identical

3 participants