Skip to content

refactor(driver-sql): move date bucketing out of sql-driver.ts into sql-driver-date-bucket.ts (#25521 cut 20) - #27127

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-p875md
Oct 28, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-p875md

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Leehom · project thread

Part of #25521
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Ruling-ref: 6348891160

维护者速读

  • 改了什么:把 sql-driver.ts 里「按日/周/月/季/年分组时,各数据库方言生成什么 SQL 分桶表达式」这一个机制(buildDateBucketExpr 的方法体)原样搬进新建的 sql-driver-date-bucket.ts;类上的方法、文档注释和签名全部保留,只把方法体转交过去,宿主接口 DateBucketHost 恰好列出方法体读的 6 个成员。
  • 为什么改:[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 拆分超大文件的第 20 刀;第 19 刀合入后重新测量,这是仍成「一个机制」、收益最大且不碰任何系列限制的区域,sql-driver.ts 减少 39 行。
  • 风险与回滚:纯搬移,无行为变化;三个 SQL 驱动的测试两端逐条一致,公开类型声明哈希不变,344 条探针读数两端一致(仅 1 条栈顶接收者名不同)。回滚即还原本 PR。
  • 先看:sql-driver-date-bucket.ts(头注释、DateBucketHost、函数体);sql-driver.ts 中 buildDateBucketExpr 的转交桩;sql-driver.ts 新增的 3 行 import。
  • 两分钟验证:pnpm --filter @objectstack/driver-sql exec vitest run src/sql-driver-date-bucket.test.ts src/sql-driver-21485-date-bucket-calendar-day.test.ts src/sql-driver-temporal-dialect.test.ts,预期全部通过。
  • 需要你做的:无,席位落地。

What changes

Cut 20 of the sql-driver.ts split (#24586 ruling A, recorded in 6270097840). The claim is 6456805734. Cut 19 (#26960) merged first, as d7f76b6d97; this cut opens with a fresh seam table taken on origin/main 6845035c6b (below) and takes the largest area that is one mechanism and moves cleanly: date bucketing, buildDateBucketExpr, from the class head. Its body moves unedited into a new seam module, packages/drivers/driver-sql/src/sql-driver-date-bucket.ts, through its host DateBucketHost.

buildDateBucketExpr is the per-dialect SQL fragment a date dimension groups by at day, week, month, quarter or year: PostgreSQL to_char, MySQL date_format, SQLite strftime, with the #21485 calendar-day arm for a Field.date and the #21595 Thursday-rule ISO week on SQLite. It returns null for a granularity the dialect does not model. Its two callers stay in the class: aggregate (the GROUP BY) and dateBucketSql (the printed form service-analytics echoes).

Why a new module. No existing seam module holds anything about aggregation or temporal read expressions; the nearest (sql-driver-schema-sync.ts) is DDL. The new module imports sql-driver.ts for a type only (import type { SqlDriver }), so it adds no evaluation cycle, and the body reads no module-level declaration, so nothing gains export and nothing else moves.

DateBucketHost lists exactly the six members the body reads, each typed as the class member (SqlDriver['NAME']): the isPostgres, isMysql and isSqlite flags and the protected dateGranularityCapabilities getter (as getters), and the protected temporalFieldKind and sqliteTemporalArg methods (as late-bound closures). All six are read by members that stay as well.

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-p875md (the platform assigned it to this card thread, as the claim records). The move is one commit, 7c6f6f1fe, on 6845035c6b.

Net line count (the seat's rule). sql-driver.ts goes from 18,406 lines to 18,367: -39.

  • Out: the body, 56 lines.
  • In: the stub body, 14 lines, and 3 import lines (a 2-line comment and the ./sql-driver-date-bucket.js import, placed after cut 16's seam import).
  • sql-driver-date-bucket.ts is new: 119 lines (a 40-line header, the type import, the 15-line host and the function with its one-line docblock).

Path readers. No test, script, doc, ADR or anchor entry reads the 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 (41) and again before opening this one (26). None touches packages/drivers/driver-sql/**.

Seam table, fresh, on 6845035c6b

Lines Section First … last member Lines 30-day Methods (public) Inferred public getBuilder sites Statics (private/protected)
1-4246 Module preamble - 4,246 698 - - - -
4247-5838 Class head: fields, statics, constructor, capability getters name … assertDialectEmits 1,592 216 8 (1) 1 0 18 (18)
5839-6270 Lifecycle connect … disconnect 432 155 8 (3) 0 0 6 (6)
6271-8677 CRUD — IDataDriver core find … delete 2,407 745 43 (7) 0 12 0 (0)
8678-9207 Bulk & Batch Operations bulkCreate … count 530 70 9 (6) 0 7 0 (0)
9208-9304 Raw Execution rawStatementFault … noteRuntimeIndexDdl 97 28 3 (1) 0 0 0 (0)
9305-9397 Transactions beginTransaction … rollbackTransaction 93 46 7 (5) 0 0 0 (0)
9398-9894 Aggregation aggregate … unresolvableAggregateColumnRefusal 497 54 5 (1) 0 1 0 (0)
9895-10156 Distinct distinct … unresolvableDistinctColumnRefusal 262 26 3 (1) 0 1 0 (0)
10157-10272 Window Functions findWithWindowFunctions … findWithWindowFunctions 116 4 1 (1) 0 1 0 (0)
10273-10371 Query Plan Analysis explain … analyzeQuery 99 1 2 (2) 0 1 0 (0)
10372-10430 Schema Sync (syncSchema / init) syncSchema … reclaimSpace 59 34 3 (3) 0 0 0 (0)
10431-11855 Schema Sync (syncSchema / init) › Data-lifecycle rotation (ADR-0057 P2) rotationStateByTable … migrateMysqlTimeColumns 1,425 219 26 (4) 0 0 0 (0)
11856-12036 Schema Sync (syncSchema / init) › Deferred schema DDL (#3917) setDeferredDdl … flushDeferredSchemaDdl 181 46 6 (4) 0 0 0 (0)
12037-12851 Schema Sync (syncSchema / init) › Managed-schema drift & reconcile (#2186) dialectName … createNullSafeUniqueIndex 815 237 23 (3) 0 0 0 (0)
12852-12903 Schema Introspection listPhysicalColumns … introspectSchema 52 46 2 (2) 0 0 0 (0)
12904-13174 Internal helpers getKnex … auditMissingTenant 271 73 8 (1) 0 1 0 (0)
13175-15224 Internal helpers › Filter helpers tableNameForBuilder … applyFalseConstant 2,050 323 44 (2) 0 0 0 (0)
15225-15400 Internal helpers › Field mapping mapSortField … mapAggregateFunc 176 2 6 (0) 0 0 0 (0)
15401-15448 Internal helpers › Window function builder buildWindowFunction … buildWindowFunction 48 26 1 (0) 0 0 0 (0)
15449-17352 Internal helpers › Column creation helper nowColumnDefault … applyDeclaredColumnDefault 1,904 101 19 (0) 0 0 8 (8)
17353-17650 Internal helpers › Database helpers sqliteFilename … isJsonField 298 76 9 (2) 0 0 0 (0)
17651-18127 Internal helpers › SQLite serialisation formatInput … formatOutput 477 27 2 (0) 0 0 0 (0)
18128-18331 Internal helpers › Introspection internals introspectColumnOrder … introspectUniqueConstraints 204 73 5 (0) 0 0 0 (0)
18332-18406 After the class - 75 0 - - - -

Pricing the areas

Eligibility is as cuts 11-19 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 per mechanism (cut 19's correction), as its stubs minus its bodies, then net of its import edits. The two leading rows were measured by running the move script on a scratch copy of the file; the rest are the stub estimate (a stub costs 4 lines, +2 per field read, +1 per method read).

Area Bodies Bodies net Declarations and imports Disposition
Date bucketing (buildDateBucketExpr) 1 -42 (measured) 0 declarations; +3 for the new module's import and its 2-line comment Moves (this cut). -39 measured.
Presumed-timestamp update (updateWithPresumedTimestamp -31, resolveUpdatedAtColumnPresence -6) 2 -37 (measured) No existing module fits; a new module costs +3 Runner-up, about -34. Not taken: smaller, and a second mechanism (⛔ no stitching). attemptWithoutPoisoning, which it calls, is shared with the autonumber module and stays.
migrateMysqlDatetimeColumns -39, migrateMysqlTimeColumns -32 1 / 1 Pinned: each wraps a vocabulary callee in a catch that logs through logDurabilityFailure, which check:durability-log-level resolves within one file only (cut 12).
Filter helpers remainder (largest presentReadValue -29) Below -30 per mechanism; the order says not to stitch them. compileFilters (-75) is refused (inferred return type).
Internal helpers tenant members (auditMissingTenant -26, applyTenantScope -25) Not taken: applyTenantScope holds 2 of the file's 4 D8 predicates (series limit); auditMissingTenant is below -30 alone.
Window function builder (buildWindowFunction) -28, orderKeysFor -27, ensureDatabaseExists -24, installQueryTiming -20 1 each Below -30 each.
Column creation members reading private statics (explainUnkeyableTextColumn -83, explainHashShadowDuplicate -66, createHashShadowUniqueIndex -62, …), ensureSequencesTable -41 Series limits: private statics stay; ensureSequencesTable writes this.

Why

Why this area, as one area

  • One mechanism. One method answers one question: "what SQL expression does this dialect group a date field by at this granularity". Its two callers and every member it reads stay in the class.
  • It pays the most of any single mechanism that moves cleanly (-39 measured, against about -34 for the runner-up).
  • No series limit is touched. The body builds through no getBuilder, reads no static, has no this.FIELD.delete/insert/update( site, uses no super or bare this, and assigns nothing to this. The method is protected with an annotated return type ({ sql: string; bindings: any[] } | null). 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 body and 0 in the module.
  • Durability gate. The body has no try and calls no logDurabilityFailure. check:durability-log-level --list prints 165 lines at both ends, identical except that two runWideningAlters seams in sql-driver.ts move 39 lines up and logDurabilityFailure's line 3 down (the import).
  • Subclasses and spies. TursoDriver overrides neither the method nor a member it reads. SqliteWasmDriver overrides the isSqlite getter; the host reads isSqlite through a getter on the driver at call time, so the override is still the one the body reads, and sqlite-wasm-driver-date-bucket.test.ts (in the wasm suite above) pins the SQL that driver emits. turso-driver.ts names SqlDriver.buildDateBucketExpr in prose, still true. The dogfood date-bucket-parity-turso.test.ts redefines buildDateBucketExpr on an instance and sql-driver-temporal-dialect.test.ts calls it through (d as any); both still reach the method, which is still on the class.
  • Path readers, screened. No script, test, doc or ADR names the member by a sql-driver.ts#… pointer or a sql-driver.ts::… key, and no scripts/adr-anchors/** record names it or date bucketing.

The shape (#23050 shape B, as cuts 1-19 apply it)

  • The class method keeps its docblock and signature, byte-identical. Its body is now one host literal plus buildDateBucketExpr.call(host, field, granularity, table), marked [#25521 cut 20]. The method is synchronous at both ends, so a failure is still a synchronous throw (probe reading 7).
  • The fields go as GETTERS that read the driver at call time, and the methods as closures that call them on the driver at call time. So a subclass override, an instance spy, or a getter overridden in a subclass is still the one the body reaches (probe readings 3, 4, 5).
  • Comments. The module header says what moved, what stayed and how the body reaches the class. The sql-driver.ts import comment names cut 20 in 2 lines. Neither cites an ADR-NNNN letter. The method's docblock (which cites ADR-0053) stays 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 1900 decision-letter citations at base 6845035c6b (a clean detached worktree) and 1900 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 body or the new header cites a decision letter, and the module is not anchored.
  • No entry needs a new home. No anchor entry names the moved member. check:adr-symbol-anchors output is byte-identical at both ends.
  • After main moved. main moved 20 commits under the cut (to 07d18e692, none in packages/drivers/**). Its tip counts 1900 letters (a clean detached worktree), and so does a local, unpushed merge of the move commit with it; both exit 0. I did not merge main into this branch: git merge-tree --write-tree of the head with it exits 0, so the tree is not stale.

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 into this worktree and removes the new module, 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 fb5f2d3313… 0bb2ccab65…).
  • The hashes. The raw sha256 of dist/index.d.ts and dist/index.d.mts is the same at base and at the move commit: 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 buildDateBucketExpr in a copy of the head index.d.ts (1 hit, then 0). The copy hashes to 1fda05673f202a32293501dc46b90afa75edd56c1dc632f66d4699af09ef3197, 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 the moved function nor DateBucketHost is among them.
  • The head dist carries the move. .call(host sites in index.mjs go from 69 at base to 70 at head (the stub).

Move-only proof

The proof compares TypeScript compiler AST leaf tokens (JSDoc nodes skipped), base 6845035c6b against the move commit 7c6f6f1fe. It is a scratch script and is not committed.

Moved body Body tokens Comments Parameter tokens less this Return type tokens Body lines
buildDateBucketExpr 423 11 20 13 56
  • The moved body. 0 tokens differ and every comment is identical. Each body line is the base line less two leading spaces. It is not async at either end.
  • The stub. 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 349 unmoved members are byte-identical, trivia included.
  • Top level of sql-driver.ts. 179 of 180 base statements are byte-identical; the other is the class. The head adds one statement, the new import (its 2-line comment is its leading trivia).
  • Result. PROOF OK, exit 0.
  • Negative control. Through scripts/ablation-replace.mjs, I changed '%x-W%v' to '%x-W%V' in the module's MySQL week arm (anchor 1 hit, then 0, checked on disk). The proof then reports buildDateBucketExpr as differing, prints PROOF FAILED, and exits 1. The restore was proved (blob 0bb2ccab65 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 6845035c6b against the move commit 7c6f6f1fe. Every part's exit code was captured on its own (build, probe, three suites: all 0 at both legs).

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
  • Type check and lint. tsc --noEmit -p . in driver-sql exits 0 on the move commit. 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 344 readings, each with the result or the error's class, message and top stack frame:
    1. buildDateBucketExpr on SQLite, PostgreSQL, MySQL and MSSQL drivers (never connected), for all five granularities plus hour and none, over a declared date, datetime, time and text field, an undeclared field, and no / an unknown table;
    2. the SQLite legacy-datetime repair arm (sqliteTemporalArg's other branch);
    3. a SUBCLASS overriding the isSqlite / isPostgres getters, and one overriding dateGranularityCapabilities (the overrides are the ones read);
    4. subclass overrides of temporalFieldKind (PostgreSQL, MySQL) and of sqliteTemporalArg (likewise);
    5. instance spies on temporalFieldKind and sqliteTemporalArg (they are the ones the body reaches, with the arguments recorded);
    6. knex replaced on the instance after construction, then restored;
    7. a failure inside the body (a throwing temporalFieldKind; an undefined capability row): synchronous throws;
    8. the callers: dateBucketSql on three dialects, and real SQLite aggregate GROUP BYs over a date and a datetime field at all five granularities;
    9. the method's shape on the prototype (type, arity).
  • Probe result. 343 of the 344 readings are identical. The other one is reading 7's undefined capability row, which differs only in the top stack frame's receiver name: NullCaps.buildDateBucketExpr at base and Object.buildDateBucketExpr at head. That is shape B's receiver, the same at every earlier cut, and no test or consumer reads it.
  • 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 48 cuts 17-19 derived). I ran each one on its own and captured its exit code before any pipe, after a full pnpm build of the move commit (116 of 116 tasks).

  • Move commit 7c6f6f1fe: 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.)
  • Hand gates, all exit 0: check-adr-anchors, check-adr-symbol-anchors, check-tenant-audit-census, 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 6845035c6b and on the move commit, check-adr-anchors, check-adr-symbol-anchors and check-tenant-audit-census print byte-identical output; check-object-def-param-keys differs only in its file count (3388 to 3389, the new module); check-durability-degradation-log-level --list prints the same 165 lines, 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 3389 files with every control firing; check:tenant-chokepoint reads 24 getBuilder() bindings across 3 files; check:durability-log-level reads 89 read seams; check:dual-build-cjs-loads loads 112 entry points across 69 packages; check:driver-conformance scores 11 of 11 dialect-scored 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-date-bucket.ts. The moved body holds 0 tenant predicates and builds no query (it returns { sql, bindings } text). 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). The module has none.
  • The series' remaining yield, priced on this base. After this cut, one single mechanism still pays more than -30: the presumed-timestamp update (updateWithPresumedTimestamp with resolveUpdatedAtColumnPresence, -37 in bodies, about -34 with a new module's import). Everything else is -29 or less per mechanism, or pinned or blocked by a series limit (the MySQL widenings, the tenant members, the private-static readers).

Human Minimum

  • 1. No packages/spec change.
  • 2. One new name, DateBucketHost, in a new module that index.ts does not re-export.
  • 3. No formatter ran; scoped eslint --no-inline-config passes (repo-wide pnpm lint is CI's run).
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. No publishable behaviour change: skip-changeset; both declaration lines above.
  • 6. packages/spec not touched.
  • 7. No hand edits to generated docs, changelogs or release notes.
  • 8. Title, body and comments are in English (the maintainer brief excepted).

Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01FEkQ5pPv99puvEK3Nmm1Mc

…ql-driver-date-bucket.ts

buildDateBucketExpr's body (the per-dialect GROUP BY expression of a date
dimension) moves unedited into a new seam module. The method stays on the
class with its docblock and signature, and hands the body exactly the
members it reads through DateBucketHost: the dialect flags and the
dateGranularityCapabilities getter as getters, temporalFieldKind and
sqliteTemporalArg as late-bound closures. Move-only: no behaviour change.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEkQ5pPv99puvEK3Nmm1Mc
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

14 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 56 of 208 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 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; 97 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 — 13 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 07d18e69275ba54653e217cb2bd61cb2b4efb1ff → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 61799fb2b7cea33c7beed5d3916d4120f2c4dd2e — the merge of head 7c6f6f1fe88db4e0a60c78e4dc8e5b73ab6d22ac into base 07d18e69275ba54653e217cb2bd61cb2b4efb1ff, 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 61799fb2b7cea33c7beed5d3916d4120f2c4dd2e && git checkout 61799fb2b7cea33c7beed5d3916d4120f2c4dd2e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 07d18e69275ba54653e217cb2bd61cb2b4efb1ff 7c6f6f1fe88db4e0a60c78e4dc8e5b73ab6d22ac && git checkout -B drift-repro 07d18e69275ba54653e217cb2bd61cb2b4efb1ff && git merge --no-ff 7c6f6f1fe88db4e0a60c78e4dc8e5b73ab6d22ac

node scripts/docs-audit/affected-docs.mjs --json 07d18e69275ba54653e217cb2bd61cb2b4efb1ff

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · domain:server seat 2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-10-28T07:36Z · head 7c6f6f1fe8 · #25521 cut 20

The maintainer's standing authorisation for landing reviewed PRs, verbatim: 「按照 pm-dispatch 规则复核过的都授权」.

  1. Shape:

    • A draft against main, assignee os-project-manager, labelled skip-changeset because this is a move.
    • The body opens with Part of #25521 (not Fixes). Clause-②: no and Metadata-protocol: none are line-initial, with Ruling-ref: 6270097840 and 6348891160.
    • check-governed-merges --pr 27127 reads NOT governed, 192 changed lines.
    • The claim (6456805734) names this PR's branch.
  2. Area against the order: cut 19's report priced the area at about −39, and the dev took it as one mechanism. Date bucketing (buildDateBucketExpr) moves into the new sql-driver-date-bucket.ts through DateBucketHost. sql-driver.ts goes from 18,406 to 18,367 lines (net −39), which clears the −30 bar.

  3. Move check (the seat's own): every non-blank line removed from sql-driver.ts against the merge base was compared with the lines added, indentation stripped. Every one of the 51 is present in the new module: 0 removed-not-added. The class keeps the method, its docblock and signature, and its callers (aggregate, dateBucketSql). The new body is one host literal plus .call:

    • getters for isMysql, isPostgres, isSqlite and dateGranularityCapabilities;
    • late-bound closures for sqliteTemporalArg and temporalFieldKind, so a subclass override or an instance spy is still the one reached.

    The module imports sql-driver.ts for a type only, so there is no evaluation cycle, and index.ts re-exports nothing from it.

  4. Published .d.ts and ADR letters:

    • The raw sha256 is 0f33bf3f… at base and at head, and the positive control changes it.
    • check:adr-anchors reads 1,900 at base, at the move, at the main tip 07d18e692, and at a local merge with it.
    • The AST proof is OK (423 tokens and 11 comments the same; 349 of 350 class members byte-identical, the one stub keeping its docblock and signature). Its negative control (%v to %V) fails.
  5. Behaviour: the three driver suites match base per test, with 0 lost, changed or added (driver-sql 4,061, driver-turso 2,526, driver-sqlite-wasm 746). The late-binding probe covers 344 readings: 4 dialects × 7 granularities × 8 field and table cases, plus the subclass arms.

  6. Gates:

    • Locally 48 of 48 derived families plus 7 hand gates exit 0, with 0 NOT-MEASURED.
    • CI on head 7c6f6f1fe8: 34 success, 18 skipped, 0 red.
  7. Overlap: git merge-tree reports no conflict against main e6e41998. No other open PR touches packages/drivers/driver-sql/**.

  8. Next: one mechanism still clears −30: the presumed-timestamp update, at about −34. Cut 21 is the series' last over the bar.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 28, 2026 07:37
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit 80064b2 Oct 28, 2026
53 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-p875md branch October 28, 2026 08:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants