Skip to content

driver-turso 住在闭源 cloud 仓,却是开源 runtime 点名偏好的默认 driver — 建议把核心迁回本仓 #4645

Description

@os-zhuang

@objectstack/driver-turso(现居 objectstack-ai/cloudpublishConfig: restricted
目标路径packages/drivers/driver-turso packages/drivers/ 目录;现有四个 driver 与它同批迁入——见「推进顺序」)
发现于:核对 #4484findStream enforce-or-remove)时,发现该 remove 的工作范围只覆盖本仓三个 driver,cloud 侧 4 处实现完全在盲区——见 #4484 的补充评论。
核实基线objectstack @ 0a936eacloud @ 0070d51(pin 在 ad5fe25
前置项#4646 / PR #4648(gate 的零发现)— ✅ 已合入

⏸️ 排期:等 maintainer 通知后再动

四条决策点已全部裁定(见文末),方案完整可实施,但实施时机由 maintainer 掌握:当前有多个 agent 在并行改 packages/plugins/driver-*#4484 正在改三个 driver 的 findStream),此时任何对这些包的路径改动都会与进行中的开发撞车。

待那批开发收尾、maintainer 通知后,一次性统一迁移——不做分批。别的 agent 请勿抢跑这个 issue。

摘要

TursoDriverextends SqlDriver 的方式跨仓库继承本仓的类,住在闭源 cloud 仓;而本仓的 runtime 已经把 turso 当一等公民——环境 provisioning 的默认偏好顺序第一位就是它。结果是:开源侧的代码路径引用着一个自己仓里既测不到、也 grep 不到的 driver,而闭源侧只能在每次 pin bump 时追赶父类的重构。

证据 0:它本来就在本仓,而且本仓至今为它保留着扩展点

CHANGELOG.md:2052-2060 记录了它的到来:

@objectstack/driver-turso plugin — Migrated and standardized the Turso/libSQL driver from @objectql/driver-turso into packages/plugins/driver-turso/. The driver extends SqlDriver

同一个 release 还做了这件事(CHANGELOG.md:2066-2073):

@objectstack/driver-sql — Protected extensibility — Changed private to protected for all internal properties and methods(knexconfigapplyFiltersformatInput/formatOutputintrospect* 等约 25 个成员)。Enables clean subclassing for driver variants (Turso, D1, etc.)

也就是说:本仓的 SqlDriver 至今维持着一整片 protected 扩展面,专为一个已经不在本仓的子类而存在——而这份扩展契约在本仓没有任何子类去行使它,等于一个无人验证的 API surface。这不是「要不要迁进来」的问题,是「它被迁出去了,接口债留在了这里」。

证据 1:开源侧已把 turso 当默认

位置 内容
packages/runtime/src/http-dispatcher.ts:1324 provisioning 偏好顺序:tursomemory → 任意其他已注册 driver
packages/runtime/src/http-dispatcher.ts:1299 POST /cloud/environmentsdriver 参数示例即 memory | turso
packages/runtime/src/default-datasource-plugin.ts:70 提到 distribution 的 turso
packages/objectql/src/engine.ts:3133 turso 专属的瞬时 fetch failed 重试
packages/objectql/src/plugin.ts:54, 88, 144 三处以 Neon/Turso 这类 latency-bound 远程 driver 为前提的设计推理(含 cold start 不被 sync 打死)

本仓有 turso 专属的容错逻辑和调度偏好,却没有 turso 的代码和测试。

证据 2:闭源侧在持续追赶父类

cloudpackages/driver-turso 最近 5 个提交里 3 个是在追本仓 SqlDriver 的内部变化

0352d3c fix(driver-turso): remote 模式的 filter 列也读进驱动的存储形态 (#937) (#1003)
eca7f7e fix(driver-turso): remote 模式的写入与 comparand 接回 SqlDriver 的 temporal seam (#937) (#942)
6d1ab28 test(driver-turso): 接入 temporal conformance 矩阵——canonical + 遗留存储四条扫描 (framework#4191) (#938)

耦合面不是「用了个接口」而是继承turso-driver.ts:166),且 find / findOne / findStream / create / update 全部带 override。父类每次重构,子类都可能静默坏掉,只能在 bump SHA 时才发现

节奏差放大了这一点:本仓最近 50 个提交跨约 11 小时;cloud 的 50 个提交跨约 2.7 天。

证据 3:仓库级 gate 与清扫物理上看不见它

scripts/check-driver-conformance.mjs 的 scope 注释写得很清楚:

packages/plugins/driver-* — discovered from disk, never listed here, so a new driver package is in scope the moment it exists

这正是迁回的直接收益:turso 落盘即入矩阵,filter 组合语义(#3774)、temporal 存储形态(ADR-0053)、确定性分页读(#4363)三套 case-set 自动 held 住它,不再靠 cloud 侧手工「接入 conformance 矩阵」(6d1ab28 就是这么补的)。

同理,#4484 那种「全仓 grep + 删实现 + 删桩」的 ADR-0049 清扫,今天必然漏掉 cloud 的 4 处实现。这类清扫是本仓常规动作,每一次都有同样的漏网风险

拆分方案

cloud/packages/driver-turso 共 4,824 行。

迁到 packages/drivers/driver-turso(~4,162 行)

  • turso-driver.ts(896)— TursoDriver extends SqlDriver,迁后变成同仓继承,父类重构立刻可见,protected 扩展面终于有子类验证
  • remote-transport.ts(961)— 纯 @libsql/client 走 HTTP/WebSocket,无任何平台机密;文件头本来就是 Apache-2.0
  • index.ts(95)、libsql-sqlite-stub.testkit.ts(87)
  • 测试:turso-driver.test.ts(1,135)、spec/turso*.{test,zod}.tsturso-{,remote-}temporal-conformance.test.ts(591)、date-bucket-parity.test.ts(135)、remote-*.test.ts(262)

留在 cloud(662 行 + service-cloud 一处)

  • multi-tenant.ts(289)+ multi-tenant.test.ts(242)— 按租户路由、{tenant} URL 模板、group token、TTL 缓存
  • vector-poc.test.ts(131)— 已核实完全独立:直连 @libsql/clientcreateClient,不 import TursoDriver;驱动四个源文件里 vector / embedding / F32_BLOB 零命中。留下来不需要从驱动里切任何东西。
  • service-cloud/src/control-plane-proxy-driver.ts — 控制面 org 注入

cloud 随后按既有的 link: + .objectstack-sha pin 消费开源版 driver;multi-tenant.ts 只 import 公开的 TursoDriver

迁完后 cloud 侧 driver-turso 包的收尾(建议,非阻塞):它将只剩一个多租户路由器和一个 vector PoC,已经不是一个 driver。两件小事值得顺手做:把包名/目录改成名副其实的(如 tenant-router),以及把 vector-poc.test.ts 挪进 packages/knowledge-turso——该文件 docstring 写明它的目的就是 "confirm before building knowledge-turso",那才是它的归属。

目录重组:packages/plugins/driver-*packages/drivers/*

五个 driver(现有 driver-memorydriver-mongodbdriver-sqldriver-sqlite-wasm + 从 cloud 迁入的 driver-turso同批落入 packages/drivers/,让 driver 与 plugin 在目录上分开。

收纳范围(已裁定)packages/drivers/ 只收 IDataDriver 实现knowledge-*(本仓 2 个 + cloud 的 knowledge-turso)、embedder-* 留在 packages/plugins/。这与 check-driver-conformance.mjs 的 scope 定义一致——该脚本已明确把「非 driver 的 case-set 消费者」排除在外,目录边界与 gate 边界因此重合,不产生第二套判断标准。

改名的影响面(已实测)

本仓

  • pnpm-workspace.yaml — 增加 packages/drivers/* glob
  • scripts/check-driver-conformance.mjs:70DRIVERS_DIRtest(drivers): a conformance run that discovers zero drivers is a failure, not an OK (#4646) #4648 已把 self-test 里的 driver-sql / >= 3 硬编码消除,现在只剩这一处常量要改)
  • .github/workflows/ci.yml:866 — 遍历 packages/triggers/* packages/services/* packages/plugins/* 的循环
  • .github/workflows/lint.yml:424 — 构建嵌套包的说明与逻辑
  • 各 driver package.jsonrepository.directory
  • packages/spec/liveness/*.json 的 evidence 路径field.jsonobject.jsonquery.json 共 11 处指向 packages/plugins/driver-sql/...)——ADR-0087 registries,路径失效即证据链断裂
  • 文档:README.md:287-289ARCHITECTURE.md:250content/docs/plugins/packages.mdx(4 处)、content/docs/protocol/objectql/{index,query-syntax}.mdxexamples/app-crm/README.md
  • pnpm-lock.yaml 重生

cloud 仓(跨仓,会断)

3 个 package.json 共 6 条 link:../../../objectstack/packages/plugins/driver-* 指向物理路径,目录一动全部失效:

  • packages/objectos-runtime/package.json:32,33,53(memory / sql / mongodb)
  • packages/driver-turso/package.json:34(sql)
  • packages/service-cloud/package.json:27,28,29(memory / mongodb / sql)

外加 lockfile 里十余条同路径 specifier。必须与一次 bump-objectstack 同批推进,否则 pin 前移时 cloud 直接装不上。

这里有个值得记下的递归:目录重组本身正好踩中它要解决的那个跨仓盲区。本仓改目录的 PR 在自己仓 CI 全绿(cloud 的 link: 路径不在本仓任何检查的视野里),破坏只在 cloud 下次 bump 时出现——和 #4484 一模一样的形状。

推进顺序

  1. 修 gate 的零发现check-driver-conformance 的 audit 路径对「发现零个 driver」报 OK — 零发现该是失败,且唯一的守卫硬编码了 driver-sql #4646 / PR test(drivers): a conformance run that discovers zero drivers is a failure, not an OK (#4646) #4648,已合入 main
  2. ⏸️ 等窗口 — 待进行中的 agent 批次收尾(含 IDataDriver.findStream 没有任何调用方,两个 driver 的实现还正好做了它承诺要避免的事(ADR-0049 enforce-or-remove) #4484 对三个 driver 的 findStream 改动),由 maintainer 通知开工。
  3. 一次性统一迁移(一个 objectstack PR + 一个 cloud PR,同批 bump):
    • packages/drivers/,五个 driver 一起进(四个从 packages/plugins/ 平移,driver-turso 从 cloud 迁入)
    • 同一 PR 内改 pnpm-workspace.yaml glob、DRIVERS_DIR、两个 CI workflow、各包 repository.directory
    • cloud 侧 6 条 link: 路径 + lockfile,配 scripts/bump-objectstack.sh
  4. 收敛文档与 packages/spec/liveness/*.json 的 evidence 路径(11 处)
  5. cloud 侧收尾:driver-turso 残包更名 + vector-poc.test.ts 归入 knowledge-turso

为什么不分批:早前版本计划「先只迁 turso,再分批搬其余四个」,理由是降低单次跨仓同步的冲突面。maintainer 裁定改为一次性,理由更强——在多 agent 并行窗口里,任何packages/plugins/driver-* 的路径改动都会与进行中的开发撞车,分批等于把这个撞车面重复 N 次;而且分批必然产生「packages/plugins/packages/drivers/ 各有 driver」的双根中间态,DRIVERS_DIR 得先改成多根扫描、迁完再改回单根,凭空多一次 gate 改动和一段需要维护的过渡状态。等窗口静默后一次做完,冲突面和改动次数都最小。

决策(已裁定)

  1. 许可/商业 — 核心 driver 迁回本仓,作为公开 Apache-2.0 包发布。
  2. 多租户边界multi-tenant.ts 的按租户 provisioning 属云产品差异化能力,留 cloud。
  3. vector-poc — 先留 cloud(已核实与驱动零耦合,留下不需要切分驱动代码;建议后续归入 knowledge-turso)。
  4. packages/drivers/ 收纳范围 — 只收 IDataDriver 实现;knowledge-* / embedder-* 留在 packages/plugins/
  5. 实施时机与批次 — 等进行中的 agent 批次收尾、maintainer 通知后,一次性统一迁移;不分批,不抢跑。

不做的代价

维持现状可行,但要接受:每次本仓 driver 契约或 SqlDriver protected 成员变更,都得有人记得去 cloud 补一刀,而这份记忆目前不在任何检查里——#4484 已经演示了它是怎么丢的。最低限度的止血是在 packages/plugins/driver-sql(或迁移后的 packages/drivers/driver-sql)加一条提示:改动 IDataDriver 契约或 SqlDriver 受保护成员时,同步检查 cloud/packages/driver-turso

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions