Repository navigation
refactor(drivers)!: 五个驱动的 query 参数跟进 DriverQuery,休眠的类型谎言没有藏身处 (#6075) - #6210
Merged
Merged
Conversation
#5181 (PR #6076) 把 IDataDriver 的六个 query 方法收窄为 DriverQuery (Omit<QueryAST, 'object'>),但五个驱动的实现仍声明 query: QueryAST (turso 侧是 query: any)。方法参数按双变比较所以它不红,可调用方现在 有权省略 object —— 实现的类型说 query.object 是 string,运行期却可能 是 undefined。这是休眠的类型谎言,不是活体缺陷:实测五个驱动没有一个 读 query.object。 把六个契约方法 (find/findOne/count/updateMany/deleteMany/explain) 的 query 参数统一为 DriverQuery,并跟进少量只转发 where/orderBy/groupBy 的私有辅助方法。收窄后「驱动读 query.object」成为编译错误 (TS2339)。 零运行时改动:非测试改动 100% 是类型注解,无逻辑、无行为、无 emit 差异。 测试面按 #5181 的迁移说明逐处重拼 —— 删掉调用字面量里冗余的 object 键; syncSchemasBatch 条目与 distinct 的 QueryInput 不在收窄范围,保持原样。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WyvqvKMG6asi9aXjKE6xtx
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 4 package(s): 15 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This was referenced Aug 7, 2026
Closed
上一版的消费半径扫描用了 `--filter 'pkg...'`(后缀省略号 = 该包 + 它
依赖的包,上游闭包),方向扫反了:签名收窄打到的是**下游**消费者。
真正该用的是前缀形 `--filter '...pkg'`,或者直接以全仓 `pnpm typecheck`
为准(CI 跑的就是全仓)。@objectstack/dogfood 因此没进上一轮扫描面。
全仓复扫命中一处真实编译错误:storage-growth.dogfood.test.ts:260 的
`cold.count(...)`,`cold` 是真实的 SqlDriver,内联字面量里的冗余
`object` 被收窄后的 DriverQuery 拒绝。
同包另有 9 处同形调用未被 tsc 标出 —— 它们走本地结构替身
`DriverLike.count(object, query?: Record<string, unknown>)`,任何键都收,
类型层看不见。一并按同一规矩删除,避免同一文件里两种写法并存。
删键用的是带反向引用的模式,只在 query 里的值与第一个实参**逐字相同**
时才匹配,等价性由模式本身保证;dogfood 包里其余 `{ object: ... }`
(权限授予、端点策略入参、report 条目、类型声明)因此一处未被波及。
⛔ 未放松任何驱动侧签名。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WyvqvKMG6asi9aXjKE6xtx
check:type-check-debt 的全仓 re-measure 报 plugin-auth 从 131 涨到 132
(+1)。plugin-auth 的 tsconfig 把 **/*.test.ts 排除在外,所以 per-package
`pnpm typecheck` 看不见它,只有把排除掀掉的全仓 re-measure 量得到。
定位到的就是一处:
src/auth-where-operator-coverage.test.ts(383,7): error TS2353:
Object literal may only specify known properties, and 'object'
does not exist in type 'DriverQuery'.
`driver.find('sys_user', { object: 'sys_user', fields: ['id'] } satisfies
QueryAST)` —— 删掉的值与第一个实参逐字相同,属重拼类。承载类型按第三类
处置改为 `satisfies DriverQuery`:该处上方注释明确写了「这里不能用 as any,
否则会被 check:query-options-erasure (#4674/#4918) 记一笔」,所以保留
satisfies、只换目标类型,正是它原本的意图。
⛔ 未抬台账数字:门禁原话「the ledger is a ratchet and may only shrink」
(#5278),本单是自己引入的 +1,属可约。改完复测回到 131,与台账记录一致。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WyvqvKMG6asi9aXjKE6xtx
os-zhuang
marked this pull request as ready for review
August 7, 2026 11:57
os-zhuang
pushed a commit
that referenced
this pull request
Aug 7, 2026
- `find()` 调用去掉 `object` 键:#6210 把驱动查询参数收窄为 `DriverQuery`, 对象名只由第一个实参给出。没有用 `as any` 绕过——拒收类测试一旦用越契约的 输入构造查询,就不再是在验证调用方真能发出的形状。 - 反向验证计数重测:LIKE 臂停用 → 8 failed / 40 passed;成员臂停用 → 4 failed / 44 passed(此前记的 32 / 36 是首写时对 40 个测试测的)。失败数 两次都不变,是承重的那一半;通过数随邻测增删而漂移,已在注释里说明。 - 补记 analytics 侧同法实测:两个门回退到 main 版本 → 17 failed / 41 passed, 而 `like-metacharacter-escape.test.ts` 在该回退下保持绿——它锁的是两包谓词 之间的一致,拒收文件锁的是门确实调用了谓词,两者都需要。 Refs #5234 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WyvqvKMG6asi9aXjKE6xtx
This was referenced Aug 7, 2026
This was referenced Aug 7, 2026
This was referenced Aug 7, 2026
Closed
This was referenced Oct 3, 2026
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Oct 7, 2026
…ts that decided them (stage 10 of objectstack-ai#20595) (objectstack-ai#21546) Part of objectstack-ai#20595 Clause-②: no ## What changed Stage 10 of the `domain:engine` lane of the dead-citation sweep: `packages/drivers/driver-turso/**`, comment and docblock prose only, per the claim (`5965451347`). Stages 1 to 9 landed as `a7d9768ec`, `d150c3039`, `4bf4e7e70`, `13a24ece2`, `db0cf2231`, `85986144c`, `48fa7a381`, `c205b6c35` and `c98a72d69`. objectstack-ai#20595 stays open: the other half of this lane is the packages this stage does not touch (`drivers/driver-mongodb` 9, `formula` 4, `metadata-fs` 2 on the census after this stage, 15 in all), plus the test-string sites the card carries for a widened stage. Every comment or docblock site in the package that cited a tracker number answering 404 is rewritten in ruling C+D's form C (record `5749154545` on objectstack-ai#19123): the ADR when one records the decision, otherwise the commit in this repository's history that made it. That is **50 sites on 49 lines in 12 files, covering 13 numbers**: - **14 census sites** (13 lines, 2 files under `src/`): the whole `allocated-but-absent` population of the gate's own census in this package at the base. `turso-driver.ts:2131` carries two of them (objectstack-ai#6076 and objectstack-ai#6075); - **36 test-comment sites** (36 lines, 10 test files), which the census defers. They carry 12 numbers: 7 the census itself reads as dead in this package's `src` (objectstack-ai#6075, objectstack-ai#12380, objectstack-ai#14428, objectstack-ai#14438, objectstack-ai#16570, objectstack-ai#16711, objectstack-ai#17690), and 5 that stand only in test files here (objectstack-ai#14434, objectstack-ai#17590, objectstack-ai#17876, objectstack-ai#17879, objectstack-ai#17970), which the board and a single read each settle; - **no site outside the census glob**: `vitest.config.ts`, `tsconfig.json`, `package.json`, `README.md` and `LICENSE` cite no dead number. No comment-id citation is dead here: the package's two comment ids, ruling records `5865693155` and `5861435168` (`remote-transport.ts:38`, `:4152` to `:4153`, `turso-20444-empty-operator.test.ts:8`), both answer 200 (see Census). **Anchors: 13 numbers by commit, 0 by ADR, 0 by repository qualifier; 12 distinct shas** (objectstack-ai#17690 and objectstack-ai#17876 share `be5c60291`: the squash of PR objectstack-ai#17876, whose message opens 「Part of」 objectstack-ai#17690). 12 numbers reuse the anchor stage 4 (`driver-sql`) measured for them; `ca3fd4b1a` (objectstack-ai#14428) is measured here. Only comments changed. Every file keeps its line count (49 lines out, 49 in, plus the changeset), so no line citation into any of them moves. No code token moves (the guard below). All 98 changed lines open with a comment marker. **No citation number is added**: on every changed line the numbers on the new text are a subset of those on the old (the only numbers on `+` lines are objectstack-ai#5181, objectstack-ai#6210 twice, objectstack-ai#6212, objectstack-ai#13878 and objectstack-ai#20987, each already on its line and each answering 200). **A `patch` changeset**: all 13 rewritten non-test lines are in the published `dist` (the `.d.ts` keeps JSDoc on exported members, and esbuild keeps these comments in the JavaScript), and `dist` is not byte-identical with the base text (see Changeset). ## H0: the package and its size The gate's own `node scripts/check-issue-citations.mjs --census --json` at base `31d2255f5` (the before run below), `allocated-but-absent` per remaining `domain:engine` package: | package | before | after this stage | |---|---|---| | `drivers/driver-turso` | **14** | **0** | | `drivers/driver-mongodb` | 9 | 9 | | `formula` | 4 | 4 | | `metadata-fs` | 2 | 2 | | `metadata-core`, `core`, `metadata-protocol`, `objectql`, `metadata`, `drivers/driver-sql`, `drivers/driver-memory`, `drivers/driver-sqlite-wasm`, `plugins/plugin-pinyin-search`, `platform-objects` | 0 each | 0 each | The lane total goes 29 to 15. `driver-turso` is the largest remaining package and reads 14, as at stage 9's head census (`99f2cfdf0`), so the stage went ahead. ## Census: `driver-turso`, before and after **Instrument (A1).** The gate's own `node scripts/check-issue-citations.mjs --census --json`, read-only and unchanged. The count is its `allocated-but-absent` findings under `packages/drivers/driver-turso/`. | reading | tree | board | whole-repo `allocated-but-absent` | sites | lines | files | numbers | |---|---|---|---|---|---|---|---| | before | base `31d2255f5`, run 04:20:17Z to 04:23:32Z | enumerated, 194 pages, frontier objectstack-ai#21537, 19,358 records | 144 | **14** | 13 | 2 | 8 | | after | `841405134`, run 04:32:36Z to 04:35:47Z | enumerated, 194 pages, frontier objectstack-ai#21539, 19,360 records (newest number read before and after the run: objectstack-ai#21539) | 130 | **0** | 0 | 0 | 0 | The whole-repo drop is 14, and the two finding sets differ by exactly the 14 rows of this package, removed; none was added. `resolves` (35,495), `resolves-as-pull-request` (2,388) and `cross-repo-unjudged` (1,247) did not move. The head's later commits are the changeset and one merge of `main`. The census was run a third time at the head `e89bd10cd` (04:53:10Z to 04:56:16Z, 194 pages, frontier objectstack-ai#21544, 19,365 records, newest objectstack-ai#21543 before and objectstack-ai#21544 after): whole-repo 130, `driver-turso` 0. Against the after run, 5 rows moved line (all in `packages/spec`, shifted by the merged `main` commit `48eb9c193`), and the finding multiset with line numbers set aside is identical. Its `resolves` reads 35,509, 14 more than above, from the merged `main` commits outside this package. **Supplementary instrument, the whole package.** The census reads neither test files nor strings nor files outside `src`. A second reading runs the gate's own exported `extractCitations` (whole-file and comment-prose projections) over every tracked file in the package (102) and classifies each citation with the gate's `classifyCitation` against one board enumerated by the gate's `enumerateBoard` (194 pages, frontier objectstack-ai#21537, 19,358 records, read 04:24:21Z to 04:27:29Z), the same board for both readings. Every one of the 13 numbers was then read on its own over the issues endpoint (04:29:27Z): **all 13 answer 404**; the numbers that stay on changed lines (objectstack-ai#5181, objectstack-ai#6210, objectstack-ai#6212, objectstack-ai#13878, objectstack-ai#20987) and the lit controls objectstack-ai#15280, objectstack-ai#12585 and objectstack-ai#6402 answer 200. | reading | citations | dead | src comment | test comment | other files | test string | changelog | |---|---|---|---|---|---|---|---| | before, `31d2255f5` | 1,921 | **83** | 14 | 36 | 0 | 6 | 27 | | after, `841405134` | 1,871 | **33** | 0 | 0 | 0 | 6 | 27 | The citation count drops by 50, the 50 rewritten sites; no respelling stays a citation. The live counts did not move (src comment: 522 resolve, 80 as pull requests, 8 cross-repo; test comment: 609, 75 and 6). A third, raw reading (every `#` followed by 2 to 6 digits, whatever surrounds it, `CHANGELOG.md` aside) counts 1,558 before and 1,509 after, and the URL-spelled issue links go 7 to 6: also a drop of 50. **Comment ids.** Every ten-digit run under `packages/drivers/driver-turso` (its `CHANGELOG.md` aside) was read: five lines. `5861435168` (the record of ruling B on objectstack-ai#20311) and `5865693155` (the record of ruling A on objectstack-ai#20399) answer 200 (the control `5965451347`, the claim, answers 200 too). `remote-canonical-backfill.ts:357` is an epoch-seconds example, not a citation. ## Per-number table `src` counts census sites, `test` the test-comment sites. Every sha matches exactly one commit (`git rev-parse --disambiguate`, count 1), is an ancestor of the base `31d2255f5` and of `origin/main` (`git merge-base --is-ancestor`, exit 0 for all 12 on both; the clone is not shallow), and resolves over the commits endpoint. The `+` lines carry exactly these 12 nine-hex spans as new ones. Each commit names the number it replaces, in its message, its diff or both: 7 in the message and the diff (objectstack-ai#6075, objectstack-ai#12380, objectstack-ai#16570, objectstack-ai#17590, objectstack-ai#17690, objectstack-ai#17879, objectstack-ai#17970), 3 in the diff alone (objectstack-ai#14428 for `ca3fd4b1a`, objectstack-ai#14438 for `2200f8ec8`, objectstack-ai#16711 for `7862fb711`), and 3 only in the subject's squash suffix (objectstack-ai#6076 for `6513c1749`, objectstack-ai#14434 for `93940d492`, objectstack-ai#17876 for `be5c60291`), where the dead number was that pull request's own and the commit is its squash. `git blame` at the base puts 24 of the 49 changed lines on their anchor; the other 25 were written by a commit that cites the number as an earlier decision (`242eb0ac1`, `9f4a6d55f`, `9bfbacbf8` and `6bd3231f6` citing objectstack-ai#12380; `3cbcedb62` and `e35c40a52` citing objectstack-ai#14438; `fa2d3b737` citing objectstack-ai#6075 and objectstack-ai#6076; `5ba2ec3ca` citing objectstack-ai#17690; `862f12c0b` citing objectstack-ai#17590; `2200f8ec8` citing objectstack-ai#14428; `ca3fd4b1a` citing objectstack-ai#14434; `7862fb711` citing objectstack-ai#16570; `eb9334915` citing objectstack-ai#17876), and in each case the anchor is the commit that made the change the sentence credits to the number. `source` says whether stage 4 already used this anchor for this number (`reused`) or it was measured here (`measured`). | number | src | test | anchor | kind | source | what it decided | |---|---|---|---|---|---|---| | `objectstack-ai#6075` | 1 | 1 | `d367f03d6` | commit | reused (stage 4, stage 5) | five drivers' `query` parameters follow `DriverQuery`; its turso diff narrows `count`'s `query` and leaves `options?: any`, the half-narrowed state both sites describe. It is the squash of PR objectstack-ai#6210, the live number kept beside it | | `objectstack-ai#6076` | 1 | 0 | `6513c1749` | commit | reused (stage 4) | `IDataDriver`'s `query` parameter becomes `DriverQuery` (that pull request's squash) | | `objectstack-ai#12380` | 2 | 6 | `4045b954d` | commit | reused (stage 4) | make the SQLite `Field.json` codec injective, one encoding across all three dialects: the local half's codec every site credits | | `objectstack-ai#14428` | 2 | 3 | `ca3fd4b1a` | commit | measured | `update()` on a missing id answers `null` on Turso's remote face; it wrote the `RemoteTransport.update()` docblock and the `turso-update-missing-id.test.ts` header the sites carry, and declared that door's record-or-null return | | `objectstack-ai#14434` | 0 | 1 | `93940d492` | commit | reused (stage 4, stage 5) | declare the not-found arm on `IDataDriver.update()` (that pull request's squash) | | `objectstack-ai#14438` | 2 | 5 | `2200f8ec8` | commit | reused (stage 4) | `update()` publishes the contract's record-or-null, not `any`, on `SqlDriver` and on `TursoDriver`'s override (the squash of PR objectstack-ai#15280) | | `objectstack-ai#16570` | 1 | 1 | `b72226f48` | commit | reused (stage 4) | declare the `indexes` key `initObjects` / `registerObjectMetadata` already read | | `objectstack-ai#16711` | 1 | 3 | `7862fb711` | commit | reused (stage 4, stage 3) | object-definition parameters declare the keys they are read for, plus the gate that sees subclass overrides; it wrote `TursoDriver.initObjects`'s docblock and `turso-driver-16711-init-objects-param.test.ts` | | `objectstack-ai#17590` | 0 | 1 | `e04a0aff2` | commit | reused (stage 4, stage 5, stage 8) | compile `$contains` on a JSON column as a per-dialect MEMBERSHIP test | | `objectstack-ai#17690` | 4 | 4 | `be5c60291` | commit | reused (stage 4) | eight more `IDataDriver` doors publish their declared return type, `TursoDriver`'s overrides among them; its message records the transaction door left un-narrowed because each of the two repairs is 「neither of which is an annotation swap」, with the 「+14 further consumer sites」 measurement, the sentence `turso-driver.ts:3549` cites | | `objectstack-ai#17876` | 0 | 3 | `be5c60291` | commit | reused (stage 4) | that pull request's squash, which installed the `ContainsAny` detector | | `objectstack-ai#17879` | 0 | 6 | `eb9334915` | commit | reused (stage 4) | measure the `ContainsAny` phantom-leg sweep across eight door pins; its message records that both repair candidates were measured | | `objectstack-ai#17970` | 0 | 2 | `47e6601c5` | commit | reused (stage 4) | collapse `ContainsAny`'s distributivity so union-shaped doors assert | No ADR or ruling record names any of the 13 numbers as the place their decision is recorded; ADR-0104 names objectstack-ai#12380 in passing, and `4045b954d` is the change these sites describe. ## Wordings to check Most rewrites swap a tag in place (`[#N]` to `[commit SHA]`, `(#N)` to `(commit SHA)`, `with #N` to `with commit SHA`, stage 1's form). These say more than the tag: - **Squash rewrites, stage 4's spellings**: 「objectstack-ai#5181 (PR objectstack-ai#6076), objectstack-ai#6075 (PR objectstack-ai#6210)」 became 「objectstack-ai#5181 (commit 6513c17), commit d367f03 (PR objectstack-ai#6210)」 (`turso-driver.ts:2131`): the dead pull-request number gives way to its squash, and the dead card number to the commit that landed its fix with the live pull-request number kept beside it as a convenience link, stage 4's 「Commit 2200f8e (PR objectstack-ai#15280)」 form. 「objectstack-ai#6075 (PR objectstack-ai#6210) narrowed」 became 「commit d367f03 (PR objectstack-ai#6210) narrowed」 (`turso-driver-options-door.test.ts:21`). 「Since objectstack-ai#13878 (PR objectstack-ai#14434)」 became 「Since objectstack-ai#13878 (commit 93940d4)」 (`turso-update-missing-id.test.ts:20`). 「`ContainsAny` (objectstack-ai#17876)」 became 「`ContainsAny` (commit be5c602)」 on three test lines. - **Reports**: 「the two measured repairs are in the objectstack-ai#17879 report」 became 「the two measured repairs are in commit eb93349's message」 (three test files), stage 4's spelling; that message records that both candidates were measured. - **`pre-` spellings**: 「restoring the pre-objectstack-ai#12380 SQLite `json` branch」 became 「restoring the SQLite `json` branch from before commit 4045b95」 (`remote-transport.ts:2612`), and 「The pre-objectstack-ai#12380 form of the string 'bare'」 became 「The form of the string 'bare' from before commit 4045b95」 (`turso-local-json-backfill-depth-limit.test.ts:72`), stage 4's 「from before commit」 form. - **A URL-spelled citation**: 「@see objectstack-ai#12380 (the injective local codec)」 became 「@see commit 4045b95 (the injective local codec)」 (`turso-json-column-type-asymmetry.test.ts:84`), stage 4's 「@see commit e04a0af (the membership construct)」 form. The three `@see` links beside it (objectstack-ai#12738, objectstack-ai#12586, objectstack-ai#11535) resolve and stay. - **The acceptance-criteria reference**: 「(objectstack-ai#16711 验收口径 item 4)」 became 「(验收口径 item 4 of the card commit 7862fb7 closed)」 (`turso-driver-16711-init-objects-param.test.ts:105`), stage 4's wording for the same sentence in `driver-sql`'s twin test, verbatim. Neither the card nor PR objectstack-ai#16816 resolves any more, so 「closed」 rests on stage 4's reading and on `7862fb711` itself: its diff names objectstack-ai#16711 32 times and creates this test file, and its message records the TS2353 negative control this paragraph introduces. - **Sentence and bullet starts**: where the number opened a sentence, a bullet or a header, the new text opens with 「Commit」: 「Commit 4045b95's codec still runs」 (`turso-json-column-type-asymmetry.test.ts:259`), 「- Commit b72226f's `indexes` fix」 (`turso-driver-16711-init-objects-param.test.ts:17`), 「// Commit 2200f8e — 」 (`turso-driver-update-declared-null.test.ts:3`) and 「⛔ Commit 7862fb7 — this parameter type must declare every key」 (`turso-driver.ts:3689`). 「* commit 4045b95 had to defeat」 (`turso-json-column-type-asymmetry.test.ts:46`) stays lower-case: it continues 「the measured … exposure that」 from the line above. - **A tag over a paragraph that says 「this card」**: `turso-driver-doors-declared-types.test.ts:117` now opens 「[commit be5c602]」, and its line 119 still says 「every door on this card had regressed to」. That line carries no number, so it was not touched; it now reads as the card behind the commit in the tag (`be5c60291`'s message opens 「Part of」 that card). - **The commit that wrote the file**: `turso-driver-update-declared-null.test.ts:3` and `:11` cite `2200f8ec8`, the commit that created that test file. Its subject is 「feat(driver-sql,driver-turso): `update()` publishes the contract's … not `any`」, so it is both the override fix the header names and the `SqlDriver.update()` narrowing line 11 credits. - No line was reflowed, so some are longer than their block's wrap (`eslint.config.mjs` declares no line-length rule, and a reflow would move neighbouring lines and every line citation into the file). ## Sites left - **In comments (src, test, outside the glob): none.** - **String literals: 6 test-string sites, 4 numbers, 4 files**: the `describe` titles at `turso-driver-16711-init-objects-param.test.ts:67` (objectstack-ai#16711), `turso-driver-update-declared-null.test.ts:85` (objectstack-ai#14438) and `turso-update-missing-id.test.ts:141` and `:223` (objectstack-ai#14428), and two assertion-message strings at `turso-json-column-type-asymmetry.test.ts:266` and `:291` (objectstack-ai#12380). All four numbers are in this stage's table. Strings are outside this stage's surface; non-test strings cite none. - **Outside `src`:** the release-owned `CHANGELOG.md` names dead numbers on 27 sites (11 numbers); left. ## Mechanical guard: no code token moves The guard (stages 2 to 9's, copied verbatim from stage 9) compares base `31d2255f5` against the tree over all 12 touched files, with TypeScript 6.0.3: - **Reading 1**: the parser's leaf nodes, from a `forEachChild` walk. Comments are trivia there, and JSDoc is never visited. A leaf that is not itself a token is re-scanned with trivia skipped. - **Reading 2**: the full token stream in parser context, from a `getChildren` walk, JSDoc nodes skipped. String, template and numeric literals are compared in full on both readings. Results, at `841405134` (the later commits touch none of the 12 files): - Real run: 38,590 base tokens, **0 files with a token change** (exit 0). - Comment control (「Keep it that way」 to 「KEEP it that way」, `turso-driver.ts`): 0 files changed (exit 0). - Positive control, an identifier (`export class RemoteTransport` to `XRemoteTransport`, `remote-transport.ts`): DIFFER on both readings (exit 1). - Positive control, a string literal (the assertion message 「… for an existing id」 to 「… for an existing iD」, `turso-update-missing-id.test.ts`): DIFFER on both readings (exit 1). - Positive control, a template literal (the index name 「uniq_ … _v」 to 「uniq_ … _w」, `turso-driver-16711-init-objects-param.test.ts`): DIFFER on both readings (exit 1). - Positive control, a numeric literal (`deepArray(1001)` to `1002`, `turso-local-json-backfill-depth-limit.test.ts`): DIFFER on both readings (exit 1). Each mutation went through `scripts/ablation-replace.mjs` (wrap mode, anchor hit 1 to 0, blob changed) under a shell trap that restores by absolute path from `HEAD`. Each restore was proven equal to its `HEAD` blob (`cc15138aba39`, `8deefdb0598b`, `e36d370cb3ed`, `f9142478172e`, `7343e92b5c7d`), with `git diff HEAD` empty and a clean tree afterwards. ## Changeset: `patch` (`dist` measured) `files[]` is `dist`, `README.md` and `CHANGELOG.md`, and the package is not private. In one script under the shared verify lock (VERDICT command-exit 0, held 104s), at `841405134`: the dependency closure was built first (`pnpm --filter '@objectstack/driver-turso^...' build`), then the package's own `build` (tsup and `check-dts-emitted`) ran three times: - **Leg 1**, the head text: 6 `dist` files hashed (`index.js`, `index.mjs`, their sourcemaps, `index.d.ts`, `index.d.mts`). All 13 rewritten non-test lines appear verbatim in `dist`. The 5 docblock lines on exported members (`remote-transport.ts:1645`, `:2601`, `:2612`; `turso-driver.ts:3689`, `:3694`) are in all four of `index.js`, `index.mjs`, `index.d.ts` and `index.d.mts`; the 8 `//` lines in `turso-driver.ts` are in `index.js` and `index.mjs`. - **Leg 2**, the base text put back in the 2 non-test touched files (2 of 2 proven equal to their base blob): 4 of the 6 files differ from leg 1 (`index.d.ts`, `index.d.mts`, `index.js`, `index.mjs`); the two sourcemaps do not. `scripts/ablation-dist-preflight.mjs` finds the base marker 「[objectstack-ai#14428] A miss answers」 in those 4 built files (exit 0). - **Leg 3**, after the proven restore (2 of 2 equal to their `HEAD` blob, `git diff HEAD` empty, porcelain empty): all 6 files are byte-identical to leg 1, and the preflight's `--absent` reading exits 0 with a clean tree, so the build is deterministic and the difference is the rewrite. So the rewrite ships, and `.changeset/20595-driver-turso-provenance-anchors.md` declares a `patch` for `@objectstack/driver-turso`, comment text only, with the claim's `Clause-②: no` line. Every anchor is a commit, so it names no ADR, repository qualifier or bracketed substitution; it says which published files carry the reworded text, as measured above. The changeset commit touches no file under `packages/drivers/driver-turso`. ## Gates (head `e89bd10cd`) - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` at `e89bd10cd` (13 paths against merge base `49161683f`, 113 changed lines) derived 65 commands. All 65 ran (04:52:21Z to 05:03:07Z, after the workspace build), each exit code captured before any pipe: 65 exit 0. `--ran` reports 「65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN」 (a derived zero) and exits 0. The PM's lead derivation (55 commands, tree `550f4cc2f`) is a subset: the extra 10 are the eight families the `.changeset/` path adds (the ADR-0087 registration and empty-changeset pairs, `check:objectui-changeset`, `check:pm-changeset-deadline-census` and two release self-tests) and two gates whose source names `packages/drivers/driver-turso/src/turso-driver.ts` itself (`check:object-def-param-keys`, `check:tenant-chokepoint`). - **Named readings:** `node scripts/check-issue-citations.mjs` exits 0 (「every citation this change adds resolves (or is a declared cross-repo reference)」: 3 judged across 2 files, the three numbers kept on `turso-driver.ts:2131`, two of them issues and one a pull request); `pnpm check:issue-citations` exits 0 (self-test, 173 cases, 9 batteries); `pnpm check:doc-authoring` exits 0 (the sibling-package prose-id baseline holds, no growth); `pnpm check:nul-bytes` exits 0 (9,888 files, no raw control bytes), and a control-byte grep over the 13 changed files finds none (exit 1). The changeset gates (`check-changeset-no-major`, `check-adr-0087-registration`, `check-empty-changeset` with `--base origin/main`, and `check:changeset-gate-self-tests`) exit 0; `check:object-def-param-keys` exits 0 (5 override parameter positions compared). - **Build, tests and typecheck, under the verify lock:** at `e89bd10cd`, the dependency closure and the package were rebuilt, then `pnpm --filter @objectstack/driver-turso test`: 88 test files pass (88), 2,365 tests pass and 33 are skipped (2,398); `pnpm --filter @objectstack/driver-turso typecheck` (`tsc --noEmit`) exits 0 (VERDICT command-exit 0, held 151s). `tsc --listFilesOnly` puts all 88 tracked test files and all 12 changed files in `tsconfig.json`'s program. The workspace build after the merge (`turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2`, 71 of 71 tasks, 1 cached; VERDICT command-exit 0, held 319s) ran before the gates. No importing package owes a run: the declaration files change only in comment text. - **Lint, as a proven narrowing, at `e89bd10cd`:** eslint with inline config disabled, over the 12 touched `.ts` files plus `dist/index.js` as the control: 13 results, 0 errors and 1 warning, the control's ignore notice; none of the 12 is reported ignored. `eslint.config.mjs` never enables type-aware linting (its lines 327 and 328 say so), so a comment edit cannot move the verdict on an untouched file. The repo-wide `pnpm lint` is CI's run. ## Acceptance notes - **Base and merge.** The dispatch read `origin/main` at `550f4cc2f`; by the time the worktree was cut, `main` had moved one commit (`31d2255f5`, `packages/mcp/server.json` only), and the branch was cut there. It merges `main` once, pinned to `49161683f` (merge `e89bd10cd`, no conflict). The two commits it brought (`48eb9c193`, `spec`; `49161683f`, `plugin-sharing` and `plugin-audit`) touch neither `packages/drivers/driver-turso`, `check-issue-citations.mjs` nor `dispatch-gates.mjs`; the closure and the workspace were rebuilt after the merge, before the tests and gates. The net diff against `main` is the 12 rewritten files (+49/−49) and the changeset (+15). - **The same dead numbers outside this package**, each left to its own carrier: `driver-mongodb` (this lane's next stage) names objectstack-ai#14428 in `src/mongodb-driver.ts` and its tests and objectstack-ai#14434 in `mongodb-update-missing-id.test.ts`, where `ca3fd4b1a` and `93940d492` are the anchors; `driver-sqlite-wasm`, which the census reads 0, still carries objectstack-ai#12380, objectstack-ai#14438, objectstack-ai#16711, objectstack-ai#17690, objectstack-ai#17876 and objectstack-ai#17879 in five test files (comments and two `describe` titles; the census defers test files, every anchor is in this table, and the comment sites are the same sentences this stage rewrote here); `scripts/check-object-def-param-keys.mjs` and `.github/workflows/lint.yml` name objectstack-ai#16570 and objectstack-ai#16711 (outside the census surface); `service-analytics`'s `contains-membership.test.ts` carries objectstack-ai#17590 in a comment, and `driver-sql`'s test strings carry objectstack-ai#12380 and objectstack-ai#17590; ADR-0104 names objectstack-ai#12380 (governed); the release pages name objectstack-ai#6075 and objectstack-ai#12380 (release-owned). - **Wording only:** no line without a number was changed. --- _Generated by [Claude Code](https://claude.ai/code/session_01DDZNkDVwPQnevTFcYE47H3)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6075
这单是什么
#5181(PR #6076)把
IDataDriver的六个 query 方法收窄为DriverQuery(Omit< QueryAST, 'object' >)。那条 changeset 自己写明了收尾未做:「把驱动签名一并迁到DriverQuery是后续的机械收尾」。这就是那次收尾。前提复核(实测 origin/main @
80f7dc6,行号以实测为准)issue 正文的行号已漂移,以下为实测:
packages/spec/src/contracts/data-driver.ts:40导出DriverQuery,:141:167:195:211:214:345六个方法都已声明它。explain是any)、turso 5 处any;sqlite-wasm 自身 0 处 ——SqliteWasmDriver extends SqlDriver,签名随基类走,本 PR 不需要动它的源码。git grep 'query\.object' origin/main -- 'packages/drivers/*/src'零命中。issue 要求复核的这一条仍然成立 ⇒ 今天没有人踩,这是休眠的类型谎言,不是活体缺陷。反向验证 —— 方向预判:红(预判写在动手之前)
本单的全部价值就是让「驱动读
query.object」变成编译错误,所以预判是标准的「把删掉的肢体装回去 ⇒ 变红」。两个方向都真跑了:after(收窄后),在
SqlDriver.find里临时写一行query.object:before(对照:把同一个签名改回
QueryAST,探针保留),TS2339 消失——谎言在收窄前编译得干干净净。该轮剩下的 134 条全部是TS2345,来自已重拼的 fixture 被改回去的宽签名拒绝,与探针无关。探针已删除(
git diff中零残留)。新增的 pin 文件
sql-driver-query-signature.test.ts也做了同样的非幻影验证:把find改回QueryAST后它四条断言全红,且第一条按方法逐个报名:改了什么
非测试改动 100% 是类型注解,无逻辑、无行为、无 emit 差异(
git diff里 4 个源文件共 33 增 32 删,逐行都是签名)。六个契约方法:
find/findOne/count/updateMany/deleteMany/explain。turso 的query: any一并收紧。跟着必须动的私有辅助方法(都只转发或读
where/orderBy/groupBy,本来就不读object;不动它们则公有方法传参处直接类型不通):buildFindOptions/buildSortSpecfields/orderByfindRows/orderKeysFororderBy/limit/offsettoRemoteQuery/toRemoteReadQuerywhere、拼orderByperformAggregationsql-driver.ts的QueryASTimport 收窄后已无使用者(余下两处是散文里的QueryASTSchema),一并删除。收窄不只是消除谎言:实测降了一批类型债
check:type-check-debt的全仓 re-measure 在本分支报出一批下降项。门禁明说下降不必付记账代价(「an improvement must not have to pay a bookkeeping toll to land」),所以台账未动;但这是本单的实际收益,值得记一笔:只有
driver-mongodb的 −33 做了归因验证,其余未归因(它们可能早于本分支就已下降,我没有度量,不替它们邀功)。mongodb 这一条是掀掉 tsconfig 的测试排除后直接对照量的:origin/main的mongodb-driver.ts(query: QueryAST)mongodb-driver.ts(query: DriverQuery)原因很直接:mongodb 的测试里本来就有一批只递
where/fields的 query 字面量,在QueryAST必填object的年代它们全是错误、被冻在 TEST_DEBT 里;收窄之后它们本来就该编译通过了。冻结面口径与一处需要维护者过目的判断
按认领评论的第三档口径,memory / mongodb 一并收紧,且硬约束是只允许改签名类型。全程遵守,但有一处值得单独说明,请复核:
memory-driver.ts的私有performAggregation(records, query: QueryInput)只解构{ groupBy, aggregations }、从不读object,但QueryInput把object列为必填,于是find收窄后传参报TS2345。处理方式是把它改成Omit< QueryInput, 'object' >—— 镜像掉同一个键,不改其余任何松紧度,因此它仍是纯签名类型改动,没有动逻辑、没有动行为、没有动断言,符合硬约束。之所以不写成DriverQuery:那会连带收紧groupBy的元素类型(输入形 vs 输出形),超出「只搬走object这一个键」的范围。若维护者认为冻结面连这一处都不该动,我可以把 memory 半边整体拆出。Fixture 三类处置(不是一把批量重拼)
收窄触发 399 处
TS2353,逐处按其守的是什么来判:driver.find(X, { object: X, where })里的object就是 [spec] IDataDriver 的 query 参数要求QueryAST.object与第一实参重复 —— 下游被迫as any(20 处实测),提议 Omit/optional 化 #5181 说的冗余——第一个实参已经是对象名。删键。每一处都核对过删掉的值与第一个实参相等(脚本比对,零处不等),所以不存在「测试原本靠 AST 的 object 覆盖实参」的情况。turso-driver.ts测试里syncSchemasBatch([{ object, schema }])的object,以及memory-driver.test.ts里distinct(obj, field, query: QueryInput)的object。这两个不是被收窄的六个方法,其中syncSchemasBatch的object是被真实读取的必填键。已逐处放回。turso-local-remote-null-parity.test.ts整份用as QueryAST拓宽字面量喂find/count,删键后该 cast 自相矛盾(TS2352)。cast 目标改为as DriverQuery,与形参对齐。remote-transport-text-predicates.test.ts的局部 helperwhere: unknown同理收成DriverQuery['where']。expand条目里的object命名的是关联对象、不是冗余,tsc 也不会标它(expand值仍是QueryAST)——已确认驱动测试里没有这类站点,未被波及。本 PR 第一版把消费半径扫反了方向,CI 因此真红过一次(
@objectstack/dogfood#typecheck)。记在这里,免得后来者照抄错命令。pnpm 的省略号是有方向的:
--filter 'pkg...'(后缀)--filter '...pkg'(前缀)签名收窄打到的是下游——那些拿具体驱动类、写内联
{ object, where }字面量的调用方。所以第一版报告里「25 个包全绿」扫的全是上游依赖,真正的消费者(@objectstack/dogfood等)一个都没进扫描面,结论完全不成立。正确做法,且以全仓为准(CI 跑的就是全仓,别再用局部闭包下结论):
(注意
typecheck在 turbo 里dependsOn: ["^build"],走 turbo 会自己把依赖建好;直接用 pnpm 递归则不会,新 worktree 里容易撞上 AGENTS.md §9 的陈旧产物陷阱。)pnpm typecheck仍然不够 —— 排除了测试的包要靠台账闸门才量得到修完 dogfood 之后全仓
pnpm typecheck是 125/125 绿的,CI 却仍红在check:type-check-debt:原因是
plugin-auth的 tsconfig 把**/*.test.ts排除掉了,per-packagetsc --noEmit根本看不见它的测试层;只有台账闸门的全仓 re-measure 会把排除掀掉重量。所以「驱动签名收窄」这类会波及测试字面量的改动,验证面必须是pnpm typecheck+pnpm check:type-check-debt两条,缺一条就会像这次一样漏。定位到的就是一处,改法照上面第 3 类:
保留
satisfies而不是改成as any,是尊重该处原有的意图:它上方的注释写明「这里不能用as any,否则会被check:query-options-erasure(#4674/#4918)记一笔」。只换承载类型,意图不变。⛔ 未抬台账数字。 门禁原话是「the ledger is a ratchet and may only shrink」(#5278),而这 +1 是本单自己引入的、属可约。改完复测回到 131,与台账记录一致,
check:type-check-debtEXIT=0。下游实际改了什么
packages/qa/dogfood/test/storage-growth.dogfood.test.ts:260,cold是真实SqlDriver),7 处走DriverLikepackages/qa/dogfood/test/group-key-read-shape-parity.test.tspackages/qa/dogfood/test/empty-group-bucket-parity.test.tspackages/plugins/plugin-auth/src/auth-where-operator-coverage.test.tsdogfood 那 9 处非强制的走本地结构替身
DriverLike.count(object, query?: Record< string, unknown >),任何键都收、类型层看不见;一并按同一规矩删掉,避免同一个文件里两种写法并存、诱导后人「修回去」。每处删键的相等性核对结论:11/11 全部相等,零处不等。 dogfood 那 10 处不是靠肉眼——用的是带反向引用的模式,只有 query 里的值与第一个实参逐字相同时才匹配:
等价性由模式本身保证,不相等的站点根本不会被匹配到。dogfood 包里其余的
{ object: ... }——权限授予(publicFormGrant)、端点策略入参(objectParams)、report.swept条目、以及interface里的类型声明——因此一处未被波及。plugin-auth 那处是单点,肉眼核对'sys_user'vs'sys_user'。⛔ 未为了让下游过而放松任何驱动侧签名。
顺带记一条反面教材(本 PR 未触,属其他包):
packages/objectql/src/engine-unknown-option.test.ts:183的engine.find('task', { object: 'person' } as any)是故意让两者不相等的拒绝测试。任何按「见object:就删」的批量清扫都会毁掉它——这正是必须逐处核对相等性、而不是无脑 sweep 的原因。验证
冻结面 memory / mongodb 测试全绿,即是零行为变化的证据。
验收 grep:
六个方法上归零。
aggregate不在IDataDriver里(distinct同理),不是本单范围。Changeset
.changeset/driver-query-signatures-follow-through.md,五个驱动包major,依据与 #5181 同一条:源码级破坏性(调用点内联字面量会TS2353),运行时行为零变化。sqlite-wasm 自身虽无源码改动,但它继承SqlDriver,公开类型面同样变了,故一并列入。check:api-surface只记录导出存在与否、不记录签名,所以这条 changeset 是该变更唯一的下游载体——这一点也是 #5181 的原话。@objectstack/dogfood是private的 QA 包、不发布,plugin-auth的改动只在测试文件、无公开面变化,两者都不进 changeset。顺带记录的发现(均未认领、observation-class)
DriverQuery收窄之外:aggregate/distinct/analyzeQuery等驱动自有查询方法仍要求把对象名写两遍 #6212 ——aggregate/distinct/analyzeQuery等驱动自有(非IDataDriver)查询方法仍要求把对象名写两遍,或干脆是query: any。DriverQuery已经存在,但几处驱动调用方仍在用as any/as QueryAST兜住冗余的object—— 连带把 where/orderBy/fields 的检查一起关掉 #6231 —— 几处调用方仍用as any/as QueryAST兜住冗余的object(metadata的database-loader、objectql的engine.ts/lifecycle-service.ts),连带把where/orderBy/fields的检查一起关掉。并行注记
PM 标注 #5907(聚合函数信封)同批在飞,触
sql-driver.ts的聚合区与remote-transport.ts。本 PR 的面是签名区与turso-driver.ts,remote-transport.ts一个字未动,零重叠;后落地者 rebase。