Repository navigation
datasource pool 声明在 sqlite / sqlite-wasm 驱动臂被静默丢弃(pg / mysql 生效) #5714
Description
Activity
分诊:决策箱(
needs-user-decision),预挂domain:services。- 过时前提检查(origin/main):
default-datasource-driver-factory.ts的 pg/mysql 臂传buildSqlPool(spec)(:365/:419),sqlite 臂走resolveSqliteDriver(:381)不传 pool;sqlite-driver-fallback.ts选项面无 pool 字段 —— declared ≠ enforced 成立,正文实测数据齐全。 - 为什么进决策箱:A/B/C 三修向(接通并对
:memory:强制{min:1,max:1}/ authoring 侧显式拒绝 / ADR-0049 enforce-or-remove)是「pool是否按驱动分契约」的公开契约形状取舍;正文已如实给出:memory:多连接互不可见的数据丢失坑,不可机械选 A,须维护者拍板。 - 域锚定:B 修向核心落点在
packages/services/service-datasource(A 亦同,连带examples/app-crm标本清理)⇒ 预挂 services;裁 C 则触packages/spec契约面,届时按 shared-contract 规则转 spec 座位。 - 在飞提示:driver-memory 测试面替代:项目内测试后端迁到 sqlite
:memory:(#5499 重启条件 · memory 半边,维护者 2026-08-06 立项) #5704(P0,driver-memory→sqlite:memory:测试面迁移,本单发现来源)同包相邻在飞;裁决落地时若其仍在飞,认领方注意同包串行与文件面申报。
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- 过时前提检查(origin/main):
裁决(2026-08-06):方案 B——sqlite 上声明
pool即 authoring 错误。authoring/publish 侧对「sqlite / sqlite-wasm 驱动臂 +
pool声明」响亮报错(错误消息说明 sqlite 连接策略由驱动决定),同批清理 app-crm 标本声明。不选 A(为零消费场景引入:memory:数据丢失防御逻辑——sqlite 在本仓的角色是 dev/test 后端);不选 C(pool在 pg/mysql 是活键,不满足 ADR-0049 全键退役前提)。公开 authoring 面收紧已获维护者授权(既有 sqlite+pool 声明会开始报错,changeset 说明)。量级 S。
⚠️ 与 #5704 迁移批次同包串行。经办:PM 会话
session_01GcjbQLUQKysMU9uXB34iyv;维护者 2026-08-06 审阅决策简报后授权按建议执行(否决窗口:可评论/重开推翻)。
Generated by Claude Code
【裁决落地】维护者 2026-08-06 批复全舰队决策箱评估报告(批复「同意」),本单裁定:
裁 B——authoring/publish 校验对 sqlite / sqlite-wasm 臂的
pool声明显式拒绝,并删 app-crm 的无效声明;声明的配置要么生效要么响亮拒绝,不许静默丢弃。⛔ 不做 A(接通::memory:必须强制 {1,1} 否则多连接互不可见,语义补丁最多)。若实现中发现「pool 按驱动分契约」(C,ADR-0049 从 sqlite 契约移除 pool)更顺,回报再议,默认 B。前提更新:分诊提示的同包在飞 #5704 已闭(08-06 08:07Z),冲突解除。
流转:摘
needs-user-decision→pm:queue,归 services 车道;若触 spec 契约面按 contract-first 拆分。评估与落地会话:
session_01N3uGFF8teXbpgtbEJ1aYXu
Generated by Claude Code
认领:PM 循环第 2 轮(services 车道)
会话:session_015a5qkLzpGXhLL2F5gvJ7dD
分支:claude/issue-5714-sqlite-pool-loud-reject
Worktree:objectstack-issue-5714
域:domain:services
文件面:packages/services/service-datasource/src/default-datasource-driver-factory.ts、datasource-connection-service.ts(若拒绝落点在此)、sqlite-driver-fallback.ts(只读核对)+ 同包测试 +examples/app-crm/src/datasources/crm.datasource.ts(删无效声明);⛔ 不触packages/spec—— 若唯一诚实落点在 DatasourceSchema,停下报 fork
串行约束已清:#5704 已闭(08-06 08:07Z,分诊在飞提示解除);⚠️ #5794(fail-fast 措辞,待分诊)可能同文件datasource-connection-service.ts—— 本单⛔不顺手修它,后轮串行执行裁决:维护者 2026-08-06 批复裁 B(authoring/publish 对 sqlite/sqlite-wasm 臂的
pool声明响亮拒绝 + 清 app-crm 标本;⛔ 不做 A;C 更顺则回报再议,默认 B),见 10:43Z 裁决评论;派发令随后。
Generated by Claude Code
验收:ACCEPT → PR #5954(CI 绿后转 ready 入队,本座位跟到 MERGED)。裁 B 兑现质量高:
- 三道门(boot 前置扫描一次点名全部违规 / 向导落库前 / 工厂构造前)+ 关键设计「authoring 判定不走
handleFailure」—— D5 降级与OS_ALLOW_DRIVER_CONNECT_FAILURE对它天然不适用且被单测钉成禁止出现(datasource fail-fast 不认识「工作区未构建」这个成因 —— 对 ERR_MODULE_NOT_FOUND 仍建议改配置或设 OS_ALLOW_DRIVER_CONNECT_FAILURE=1(两条都是有害建议) #5794 教训的在仓先例);active:false豁免的理由(不炸掉运维摘下线的补救路径)与 ADR-0062 D2 形状的判全体声明,推理都成立。 - 真实 boot 双向验证是本单最有说服力的证据(app-crm 塞回声明 → 启动拒绝且消息即修法;删声明 →
✓ Server is ready+ 28 rows);自抓「读旧 dist 假绿」并写进 PR 防后人踩,好记录。 - 边界两条(插件驱动不判 = datasource.config 至今无人校验:驱动 configSchema 是声明但完全惰性的(ADR-0049 enforce-or-remove,#4001 收尾发现) #4410 线;memory 不并入 = 裁决授权边界,立 datasource
pool声明在 memory 驱动臂同样被静默丢弃(#5714 的姊妹臂,裁决未覆盖) #5931 并在模块注释指名)——克制正确。 - app-showcase 第二标本与
drivers.mdx「honoured for every SQL driver」纠偏,属一致性半径,接受(文件面越界已在报告申报)。 - 必答项 datasource fail-fast 不认识「工作区未构建」这个成因 —— 对 ERR_MODULE_NOT_FOUND 仍建议改配置或设 OS_ALLOW_DRIVER_CONNECT_FAILURE=1(两条都是有害建议) #5794:同文件不同行段、其消息块一行未动(仅整体下移),「略变简单总体无影响」—— 已核,datasource fail-fast 不认识「工作区未构建」这个成因 —— 对 ERR_MODULE_NOT_FOUND 仍建议改配置或设 OS_ALLOW_DRIVER_CONNECT_FAILURE=1(两条都是有害建议) #5794 待分诊后照常独立处理。
两个 open question 的 PM 裁定(范围/排程类,不上呈):
- Q1 裁 A(维持现状)。B(spec 侧 superRefine 按驱动拒 pool)是裁决明文标为 C、须再议的公开契约形状变更,且其增量收益(parse-but-never-boot 场景)今天仓内零消费者 —— 按创业聚焦不立投机单。其中「Studio 表单对 sqlite 不渲染 pool 字段」半边有真实 UX 价值,但同属 C 的语义面:待出现真实作者困惑证据时携证立单再议。本裁定记录于此,维护者可否决。
- Q2 裁 B-作为-datasource
pool声明在 memory 驱动臂同样被静默丢弃(#5714 的姊妹臂,裁决未覆盖) #5931 的 rider:packages/spec/liveness/datasource.json四行 pool 键的按驱动限定注记,并入 datasourcepool声明在 memory 驱动臂同样被静默丢弃(#5714 的姊妹臂,裁决未覆盖) #5931 的处置轮次(注记内容依赖 datasourcepool声明在 memory 驱动臂同样被静默丢弃(#5714 的姊妹臂,裁决未覆盖) #5931 的最终裁定 —— memory 若并入拒绝集合,注记覆盖三个臂)。已在 datasourcepool声明在 memory 驱动臂同样被静默丢弃(#5714 的姊妹臂,裁决未覆盖) #5931 留痕,不塞本 PR。
经办:services 座位,会话
session_015a5qkLzpGXhLL2F5gvJ7dD(第 2 轮)。
Generated by Claude Code
- 三道门(boot 前置扫描一次点名全部违规 / 向导落库前 / 工厂构造前)+ 关键设计「authoring 判定不走
队列管家知会(services 车道):#5954 落地后引入了一条队列级抖动,根因在本单的新测试文件
本单 PR #5954(
99d7a93)13:15:31Z 落地。13:52:34Z 起,它新增的测试开始在合并队列里踢无关 PR。 首个受害者是 spec 车道的 #5973(diff 只碰packages/spec/src/contracts/sharing-service.ts,与 datasource 零关系),已在该 PR 留判读并未重投。本条只知会根因位置,⛔ 本座位不改代码、不入队。签名(完整日志归档,run 31108010067 → job
Test Core (1/3)):FAIL src/__tests__/datasource-pool-support.test.ts > #5714 — the driver factory rejects a pool it cannot honour > sqlite WITHOUT a pool still builds exactly as before Error: Test timed out in 5000ms. ❯ src/__tests__/datasource-pool-support.test.ts:122:3实测 5073ms,超默认阈值 73ms —— 边界抖动。
为什么它没有护栏(读数取自
origin/main):@objectstack/service-datasource没有vitest.config.ts⇒ 跑 vitest 默认testTimeout: 5000。fix(spec): 给 packages/spec 的 vitest 设 testTimeout 60s —— 止血,不再把无关 PR 踢出合并队列 (#4850) #4856 那次全仓性的testTimeout: 60_000是包级的,只在packages/spec/vitest.config.ts,从未覆盖本包。:122这条用例做的是一次真实 sqlite 驱动构建(await factory().create({ driver: 'sqlite', config: { filename: ':memory:' } })),却未带显式超时。- 而同包同类的慢用例是带的:
default-datasource-driver-factory.test.ts的三条真实构建用例各挂}, 30_000);其中builds a file-backed SqliteWasmDriver that connects and round-trips在同一个 run 里跑了 9007ms 并通过。同一类工作,一边有护栏一边没有——这就是差额。
同 run 的
Duration行报import 21.11s,即 runner 侧 import 开销本身就吃掉相当预算,5000ms 对「真实驱动构建」类用例本就不是一个安全的默认。观测到的频率(如实给数,不夸大):自
99d7a93落地到 14:30Z,20 个已完成的 merge_group CI run 里红 1 个(~5%),其余全绿。是间歇性的,不是必红——但它踢的是队列里任何一个 PR,与那个 PR 的 diff 无关,属共享损伤(SKILL note 10 的形状)。建议修法(车道自行判定,本座位不代做决定)——两条都在本包内,量级 XS:
- 给
:122(以及本文件其余做真实构建/连接的用例)挂显式超时,与同包既有惯例}, 30_000)对齐;或 - 给
packages/services/service-datasource补一个vitest.config.ts设包级testTimeout,一次覆盖本包后续所有真实驱动用例(更彻底,且本包按 datasourcepool声明在 sqlite / sqlite-wasm 驱动臂被静默丢弃(pg / mysql 生效) #5714 的方向会继续长真实构建类测试)。
⚠️ 提醒一处范围外但同源的风险:#5931(memory 臂并入拒绝集合的后续单)若继续在本包加真实构建用例,同一个默认 5000ms 会再咬一次——所以第二种修法可能更省事。让行核验:本单最近 30 分钟零评论(最后一条是 12:59:47Z 的 ACCEPT 回报)⇒ 无双重处置。本条是知会,不是认领,⛔ 本座位 assign 恒为 0。
Generated by Claude Code
- added a commit that references this issue
on Aug 22, 2026 - added a commit that references this issue
on Aug 23, 2026
发现于 #5704 批次 0 的迁移工作(把
datasource-autoconnect.test.ts换到 sqlite:memory:时核对连接池行为),与该 PR 无关,单独记录。事实
createDefaultDatasourceDriverFactory的postgres/mysql臂都把buildSqlPool(spec)传给SqlDriver,而sqlite臂走resolveSqliteDriver(...),完全不传 pool:packages/services/service-datasource/src/default-datasource-driver-factory.ts— sqlite 分支只传filename/dev/schemaMode/autoMigrate。packages/services/service-datasource/src/sqlite-driver-fallback.ts—ResolveSqliteDriverOptions根本没有 pool 字段,buildNative()构造SqlDriver时也没有。sqlite-wasm臂同理(SqliteWasmDriver也不接 pool)。实测(worktree,service-datasource dist,通过工厂真实构造)
sqlite 拿到的是 knex sqlite dialect 自己的默认值,声明的
{min:3,max:9}没有到达任何地方,也没有任何提示。现网标本:
examples/app-crm的CrmDatasource声明了pool: { min: 1, max: 5 }(examples/app-crm/src/datasources/crm.datasource.ts),实际得到{min:1,max:1}。为什么值得记一笔
这正是 #4410 那一轮在清的「声明了但没人读」的形状 ——
datasource.pool是 strict schema 上的可授权键,pg/mysql 认它、sqlite 不认,差异既没文档也没告警。但修法不是简单接上去(所以这里不带方案)
对
filename: ':memory:'的 sqlite,照着max大于 1 接上去反而是错的:knex 的 better-sqlite3 每取一条连接就new Database(':memory:'),即开出一个互相看不见的空库,写进 A 读不到 B。knex 自己的 sqlite dialect 默认{min:1,max:1}就是为了躲这个坑。所以三条路各有代价,需要裁决而不是猜:
:memory:引入静默数据丢失 —— 除非同时对:memory:强制{min:1,max:1}。pool时在 authoring / publish 校验里报错并说明「sqlite 连接池由驱动决定」,契约优先,作者立刻知道。同时要把 app-crm 的声明删掉。pool:走 ADR-0049 enforce-or-remove。倾向 B 或 C(取决于
pool是否按驱动分契约),但这是公开契约形状问题,留给维护者定。复现脚本(在
packages/services/service-datasource/下,先 build):