Skip to content

test(driver-turso): 双传输各跑一遍 FILTER_LOGIC / PAGINATION 共享 case-set,清掉三条 DEBT (#5590) - #5656

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-5590-turso-conformance-suites
Aug 5, 2026
Merged

test(driver-turso): 双传输各跑一遍 FILTER_LOGIC / PAGINATION 共享 case-set,清掉三条 DEBT (#5590)#5656
os-zhuang merged 1 commit into
mainfrom
claude/issue-5590-turso-conformance-suites

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #5590

做了什么

packages/drivers/driver-turso 补四个套件,从 @objectstack/spec/data 导入并驱动 FILTER_LOGIC_CASES / PAGINATION_CASES / PAGINATION_UNORDERED_CASES每格两面——照同包 temporal 那对套件的形状:

文件 传输面 引擎
turso-filter-logic-conformance.test.ts local :memory:(better-sqlite3 + knex)
turso-remote-filter-logic-conformance.test.ts remote libsql-sqlite-stub.testkit.ts
turso-pagination-conformance.test.ts local :memory:
turso-remote-pagination-conformance.test.ts remote libsql-sqlite-stub.testkit.ts

四个都 hermetic:不要网络、不要凭据、CI 默认跑。四个全绿,所以同一个 commit 里把 scripts/check-driver-conformance.mjs 的三条 DEBT 条目删干净(⛔ 判定函数一行未动,只动 LEDGER 数组与它的说明注释)。

为什么"继承所以没问题"不成立——这也是套件的内容主张

TursoDriver 是双传输的。local/replica 继承 SqlDriver;remote 完全不走 knex,src/remote-transport.ts 自带 buildWhereSQL(组合子嵌套、算子词表、比较值拒收、空组合子的布尔单位元)和自己的 ORDER BY / LIMIT / OFFSET 拼装。这就是 #3774 / #4363 设共享 case-set 要压的"独立实现的第 N 个后端"。

反向验证(先定方向再跑,三个都按预测走)

  1. 把 remote buildWhereSQL 的顶层 clauses.join(' AND ') 改成 ' OR 'driver-sql: $or branch contents are OR-ed instead of AND-ed, widening every $or filter #3774 那个缺陷的形状)→ 预测 remote 套件红、local 套件绿。实测 remote 16 红、local 全绿,例如
    multi-key $or branch ANDs its own keys: expected [ '1', '2', '3' ] to deeply equal [ '1' ]
  2. 让 remote buildSelectSQL 只在非分页读上拼 ORDER BY → 预测 remote 分页套件红、local 绿。实测 remote 6 红(5 条 page boundaries are invisible + 机制 pin),local 全绿。
  3. TursoDriver.find 的 local 分支里把调用方 orderBy 丢掉(打的是本包自己的传输路由层,正是 local 套件模块注释声称在钉的东西)→ 预测 local 分页套件红、remote 绿。实测 local 5 红,remote 全绿。

三次都是"一面红另一面绿",正好把 issue 的前提——两条传输是两套实现,一面的套件看不见另一面的回归——直接测了出来。

(顺带记一个诚实的强度边界:第 2 个 mutation 下 visits every row exactly once 仍然绿,因为丢掉 ORDER BY 后 rowid 序仍是一个 partition。这正是 case-set 自己说的"性质"和"那条子句"是两回事,所以 page boundaries are invisible 与机制 pin 才是这两个套件里带牙的断言。)

remote 分页这两格是绿的,但请连着这段一起读

buildSelectSQL 把调用方的 orderBy 原样透传、不追加唯一列;local 面走的是 SqlDriver.orderKeysFor(),按 #4363 的三态表补 id tie-breaker。实测 remote 面 ORDER BY status ASC 的并列组内是插入序而非 id 序,无序分页读则是 rowid 序:

remote sorted:    r03,r09,r02,r10 | r01,r12,r08,r06 | r07,r11,r05,r04
remote unordered: r07,r03,r11,r01,r09,r05,r12,r02,r08,r04,r10,r06

也就是说:remote 面满足了这些 case,但不是靠契约点名的那个机制——是靠 stub 那张 12 行内存表计划固定。真实 endpoint 上并列行的排布不被 SQLite 承诺在两条语句之间一致,而 pagination-conformance.ts 自己的模块注释就写明无序读是同一缺陷的满强度形态、driver-memory 那条"存储顺序稳定"的豁免针对的是 JS 数组不是 SQL 计划。

按本单边界(套件里不修实现、不给自己发准考证),这条缺陷另开单#5653。remote 套件里留了两条 records the measured mechanism 测试把当前"没有 tie-breaker"的事实钉住——#5653 落地那天它们会红并随之改写,而不是让这条分叉在一个绿格子底下悄悄躺着。gate 注释里也记了同一件事(放注释而不是 LEDGER 条目:格子确实已覆盖,给已覆盖的格子留条目会判 RECONCILED 红)。

验证

$ npx vitest run --maxWorkers=2         # packages/drivers/driver-turso 全量
  Test Files  19 passed (19)
       Tests  621 passed (621)          # 迁入时是 15 files / 逐步增至 19

$ pnpm check:driver-conformance         # 含 --self-test
  driver-turso        ok  ok  ok  ok  ok
  check-driver-conformance: OK — 25 covered cell(s), 0 in the DEBT ledger, 0 exempt.
  OK  self-test: detects driven / unused / re-declared fixtures, discovers both axes, …

$ pnpm --filter @objectstack/driver-turso typecheck     # tsc --noEmit,无输出
$ npx eslint <5 个变更文件> --no-inline-config           # exit 0
$ node scripts/check-query-options-erasure-ratchet.mjs
  ✓ query-options-erasure ratchet holds: 84 unswept non-test site(s) in 19 file(s), none new.
    test surface: 267 site(s) in 51 file(s) — at the ceiling.     # 新套件零新增擦除站点
$ node scripts/check-nul-bytes.mjs
  check-nul-bytes: OK (scanned 5573 tracked text file(s); …)

query-options 类型:四个新套件的 query 从第一行就是正确类型,没有一处 as anyfind/count 的签名本就 any,直接传字面量即可),所以 267 天花板纹丝不动。

边界

Changeset

测试 + gate ledger,不发布任何包 → 按 pr-automation.yml 的路线 2,请挂 skip-changeset 标签。


🤖 Generated with Claude Code

https://claude.ai/code/session_01WyvqvKMG6asi9aXjKE6xtx


Generated by Claude Code

…on BOTH transports, clearing the three DEBT cells (#5590)

`TursoDriver` is dual-transport. Local/replica inherits SqlDriver's filter
compiler and its paged-read tie-breaker; remote does not go through knex at
all -- `src/remote-transport.ts` carries its own `buildWhereSQL` and its own
ORDER BY / LIMIT / OFFSET assembly. That is the independent Nth backend
objectstack#3774 and objectstack#4363 wrote the shared case-sets for, so each
cell takes two suites, one per transport, in the shape the temporal pair in
this package already established:

  turso-filter-logic-conformance.test.ts          local, :memory:
  turso-remote-filter-logic-conformance.test.ts   remote, sqlite stub
  turso-pagination-conformance.test.ts            local, :memory:
  turso-remote-pagination-conformance.test.ts     remote, sqlite stub

All four are hermetic -- the remote half runs over
`libsql-sqlite-stub.testkit.ts`, so no network and no credentials -- and all
four are green, which is what lets the three DEBT entries leave the ledger in
this same commit (25 covered cells, 0 DEBT).

The remote PAGINATION half passes WITHOUT the mechanism the contract names:
`buildSelectSQL` maps the caller's `orderBy` verbatim and appends no unique
column, so the cases hold on a twelve-row better-sqlite3 table rather than by
a promise the transport makes. Filed as objectstack#5653 and stated plainly in
both the suite's module doc and the gate's ledger note; two `records the
measured mechanism` tests pin the current no-tie-breaker behaviour so it
cannot go quiet under a green cell. Per this issue's boundary the transport
itself is untouched here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WyvqvKMG6asi9aXjKE6xtx
@vercel

vercel Bot commented Aug 5, 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 5, 2026 10:21pm

Request Review

@github-actions github-actions Bot added the tests label Aug 5, 2026
@os-zhuang os-zhuang added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 5, 2026 — with Claude
@github-actions github-actions Bot added the size/l label Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

2 participants