## 问题 `recomputeSummaries` 在子记录写入成功后重算父对象的 summary 汇总字段时,把每个父记录的 aggregate + update 包在 try/catch 里,失败**只打一条 warn 日志**——不抛出、不重试、不计入任何面向调用方的结果。 位置:[packages/objectql/src/engine.ts(recomputeSummaries,catch 分支)](https://github.com/objectstack-ai/framework/blob/021ba4caf/packages/objectql/src/engine.ts#L1827-L1833) 后果:子记录批量插入返回**全部成功**,但父记录的汇总值(如发票 `total`)静默保持过期/缺失。远程 DB(turso)一次网络抖动落在"父汇总 update"上,就得到一笔明细正确、总额错误、无人知晓的数据。seed / import 层的 `withTransientRetry` 罩不到这里,因为它发生在 `engine.insert` 内部。 ## 复现(探针测试,可直接作为回归用例) 用 mock 驱动让 `update('inv', ...)` 第一次抛 `fetch failed`: ```ts // inv.line_total = summary SUM(inv_line.amount);驱动 update(inv) 首次抛 'fetch failed' const a = await engine.insert('inv', { name: 'A' }); const res = await engine.insert('inv_line', [ { name: 'l1', amount: 10, inv: a.id }, { name: 'l2', amount: 7, inv: a.id }, ]); // 实测:res.length === 2(全部报成功),而父记录 line_total === undefined(汇总永远没写上) // 日志仅出现:WARN Roll-up summary recompute failed ``` ## 建议修法 1. `recomputeSummaries` 内部对 aggregate + 父 update 加 transient 退避重试(与 `@objectstack/core` 的 `withTransientRetry` 同语义)。 2. 重试耗尽仍失败时,失败必须对调用方可见:抛出,或至少在返回结果/操作上下文中带出"汇总重算失败"信号,不能只 warn。 ## 验收标准 - 父汇总 update 首次抛 transient 错误 → 重试后汇总值正确落库。 - 重试耗尽仍失败 → 调用方能从返回值或异常中感知,不再是静默成功。 - 上述探针场景由红转绿并入正式测试套件。 —— 发现于 #2678 批量写入路径专项测试(测试报告见该 issue 评论)。
Activity
chore: add changeset for bulk-write hardening (#3147–#3152)
fix: harden the bulk-write path — retries, idempotency, contracts, su…
test(runtime): real-SqlDriver regression for the bulk-write hardening (…
test(runtime): real-SqlDriver regression for the bulk-write hardening (…
test(runtime): real-SqlDriver regression for the bulk-write hardening (…