Skip to content

fix(driver-turso): narrow every override's options from any to DriverOptions (#6402) - #6755

Merged
os-zhuang merged 3 commits into
mainfrom
claude/issue-6402-turso-driver-options-narrowing
Aug 8, 2026
Merged

fix(driver-turso): narrow every override's options from any to DriverOptions (#6402)#6755
os-zhuang merged 3 commits into
mainfrom
claude/issue-6402-turso-driver-options-narrowing

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #6402

What was open

TursoDriver overrides methods that take an options argument and declared every one of them options?: any, while the base they forward to (SqlDriver, and behind it the IDataDriver contract) declared DriverOptions. The keys DriverOptions names — bypassTenantAudit, tenantId, transaction, accessible_org_ids, skipCache, timeout, … — were unchecked at every one of those doors.

The argument is #5181's, one axis over. An internal caller that misspells bypassTenantAudit gets no runtime complaint: the typo'd key is simply never read, the write proceeds unaudited, and nothing anywhere says so. tsc is the only channel that ever objects, and any had switched it off.

Nothing is known to have gone wrong through this gap. It is closed because the door was open, not because someone walked through it — the issue was filed and triaged as observational.

⚠️ Premise correction: 17 sites, not five

The issue's count is wrong, and the correction changes the scope rather than a detail. #6402 names five overrides (update, upsert, delete, count, aggregate) — the CRUD block its author was reading while #6212 batch B was in flight. Measured against main, turso-driver.ts carries 17 options?: any sites:

Block Overrides
CRUD find, findOne, create, update, upsert, delete, count, aggregate
Bulk bulkCreate, bulkUpdate, bulkDelete, updateMany, deleteMany
Raw execution execute
Schema syncSchema, syncSchemasBatch, dropTable

This matters because of the issue's own binding rule: an identical shape must not be partially narrowed, since a subset reads to the next person as a verdict on the rest. Narrowing the five named would have reproduced that exact anti-pattern at larger scale — leaving twelve character-identical any doors behind, in the very PR filed to stop that from happening. All 17 are narrowed here, so no half-narrowed state exists to be misread.

The dispatch ruling scoped this to "all five together, or a reasoned do-not-narrow verdict, never a partial narrowing". Narrowing all 17 satisfies both the letter (the five are included) and the intent (no residue). Flagging the scope change explicitly since it exceeds the literal ruling.

Also measured: turso-driver.ts was the only driver in the repo with this shape. Every other driver already declared DriverOptions. The remaining repo-wide options?: any hits are narrow structural port interfaces in objectql / service-job / service-queue / service-automation, which is a different axis and out of scope.

The measurement the issue asked for

#6402 explicitly made this a precondition: "我没有量过:这五处 override 的实际调用方是否都已经在传 DriverOptions 形状的值 … 收窄前应先跑一遍这个量。"

Run, on all 17: turbo run typecheck is 125/125 green, unchanged. No caller in this repo passes an off-contract value, so the narrowing is annotation-only — the same result #6210 measured on the query axis. No call site needed a cast, and none was added.

Reverse verification — direction predicted per channel BEFORE it was run

Reverted all 17 signatures to options?: any and measured both channels:

Channel Predicted Measured
pnpm typecheck RED, one error per reverted signature, plus TS2578 on the misspelling pin 18 errors: 17 × TS1360, one per table row, + 1 × TS2578
pnpm test GREEN — every assertion is a type-level fact 4/4 passed

That split is the finding, not an inconvenience: this defect has no runtime face at all, which is why it sat unnoticed 17-for-17. It also means the pin had to be built as a compile-time check to have any teeth.

One prediction was written imprecisely and corrected against the measurement: the doc comment first said the revert fails with an assignability error; the actual code is TS1360 (does not satisfy the expected type), because the rows use satisfies. The comment now quotes the real message.

Tests

New turso-driver-options-door.test.ts pins all 17 doors. Door<T> reports 'any' for a widened door and 'DriverOptions' only for an exact match; each row then satisfies it, so reverting any single signature fails tsc on that row, naming the method that drifted.

A mutual-extends check could not do this — any satisfies both directions and would have reported green. The IsAny<T> = 0 extends 1 & T detector is what makes the pin real, and the revert above is the evidence it works rather than an assumption that it does.

The suite also carries a positive control (declared keys still fit, so the pin is not green merely because nothing fits) and a @ts-expect-error case on the exact misspelling the issue argued about — bypassTenantAdit. That directive tripping TS2578 under revert is what proves the excess-property check is live.

No existing test turned red, so nothing needed fixing and no cast was introduced to silence anything.

Verification

  • pnpm --filter @objectstack/driver-turso test840/840 passed, 28 files
  • pnpm --filter @objectstack/driver-turso typecheck — clean
  • turbo run typecheck (packages, packages/*/*, apps) — 120/120; full monorepo 125/125
  • pnpm --filter './examples/*' run typecheck — clean (4/4)
  • turbo run build (packages + examples deps) — 70/70 and 66/66
  • All 64 steps enumerated from .github/workflows/lint.yml — run one by one, every check:* in the ESLint and TypeScript Type Check jobs. All pass, including check:query-options-erasure (turso is not baselined — that ratchet targets engine query-options; the new test adds no erasure and leaves testSurface.sites alone), check:driver-conformance, check:driver-memory-census, check:type-check-debt, check:exported-any, check:published-files.
  • pnpm lint — clean

Re-run in full after merging origin/main at 64d764e.

Notes


Generated by Claude Code

@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 8, 2026 2:22pm

Request Review

@github-actions github-actions Bot added the size/m label Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/driver-turso.

6 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/data-modeling/drivers.mdx (via @objectstack/driver-turso)
  • content/docs/deployment/cli.mdx (via @objectstack/driver-turso)
  • content/docs/deployment/environment-variables.mdx (via @objectstack/driver-turso)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/driver-turso)
  • content/docs/getting-started/glossary.mdx (via @objectstack/driver-turso)
  • content/docs/plugins/packages.mdx (via @objectstack/driver-turso)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Aug 8, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 8, 2026 15:20
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 8, 2026
Merged via the queue into main with commit fa2d3b7 Aug 8, 2026
25 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6402-turso-driver-options-narrowing branch August 8, 2026 15:34
os-zhuang pushed a commit that referenced this pull request Aug 9, 2026
`SqlDriver` 的 `create/find/update/delete` 声明的是 `options?: DriverOptions`,
`bypassTenantAudit` 是 `DriverOptionsSchema` 上的合法键(spec 17.0.0 起,
#4311),所以这些转型早就不需要了。它们不是无害的:转型关掉的是**整个选项
对象**的检查,于是这些站点上任何键名拼错都不报错。

`TursoDriver` 一并纳入:PR #6755(#6402)已把每个 override 的 `options?: any`
收窄成 `options?: DriverOptions`(实测 `options?: any` 计数为 0),turso 当初被
单独拆出去的唯一理由已经消失;#6394 也已落地,`bypassTenantAudit` 上的
`as never` 残留为零。留着这 4 处就没有第二个人来收。

逐包实测(依赖闭包先构建,避免读到过期的 `dist/*.d.ts`):

| 包 | 剥掉 | 文件 |
|---|---:|---:|
| driver-sql | 11 | 6 |
| driver-sqlite-wasm | 19 | 8 |
| driver-turso | 4 | 2 |
| **合计** | **34** | **16** |

`driver-sqlite-wasm` 实为 19 而非单据说的 17/18:第 19 处是
`sqlite-wasm-pagination-conformance.test.ts:34`,形状是
`as unknown as Parameters<SqliteWasmDriver['find']>[2]`,单据的窄 grep 匹配
不到。`driver-memory` / `driver-mongodb` 的转型站点为 0。

两处具名 const(`sql-driver-limit-zero-presence.test.ts` 的 `READ`、
`sqlite-wasm-pagination-conformance.test.ts` 的 `READ_OPTIONS`)只删转型**不
足以**换回检查:超额属性检查只对直接位置上的新鲜字面量生效。实测确认,
`const READ = { tenantId: 't1', bypassTenantAuditt: true }` 在只删转型的情况下
EXIT=0、零报错 —— 拼错被静默吞掉。因此这两处改为 `: DriverOptions` 标注,让
字面量在声明处受检。

⛔ 未触碰 `packages/objectql/src/engine-unknown-option.test.ts` 的 2 处:另一个
包、另一种形状(转型套在传给 `engine.find(...)` 的查询对象上,不是
`DriverOptions` 参数),且 `bypassTenantAudit` 出现在该文件自己的 `PASSTHROUGH`
漂移钉里 —— 剥掉等于删掉被测对象。属 engine-core 车道。

同样保留:两处 `find(..., {} as any, ...)` 里的**查询**参数转型 —— 被测对象是
查询而非选项,属 #4918 的擦除家族,不在本卡范围。

纯测试改动,无 changeset(走 `skip-changeset` 标签,route 2)。

Refs #6754, #6394, #6402, #6755

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MVa7roTgq6gGty2bG2KiEf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding][drivers] TursoDriver 五个 override 的 options?: any —— #5181 收窄的是 query,options 这条轴还没人碰过

2 participants