## 问题 `OutcomeRepository.saveOpinion()` 和 `saveOutcome()` 分别读取整个 `outcomes.json`,修改一个集合后覆盖写回。`JsonFileStore` 的原子替换只保证文件完整,没有保护仓库的读改写过程。两个保存操作重叠时,会基于同一旧快照写入,静默丢失其中一次更新。 这不只影响同时保存两个观点:`kernelHost.ts` 的研究完成回调调用 `createOpinionFromReport()`,启动及手工评估路径调用 `evaluateDue()`,两条路径共用同一个仓库文件,因此新观点和到期评估结果也会相互覆盖。 ## 复现与预期 基线:main `a6da0059ecafe4426c9a841ec59215655ebcabd1`。 对真实临时目录中的 `JsonFileStore.read()` 增加 20ms 延迟以放大重叠窗口,执行: ```ts await Promise.all([ repository.saveOpinion(newOpinion), repository.saveOutcome(completedOutcome), ]) ``` 实际:一份旧快照覆盖另一份更新,新观点或评估结果消失;操作均成功返回。 预期:同一文件的两类读改写应串行化,两份更新均可从新建仓库实例读回。 ## 验证 环境:Bun 1.4.2 / Windows 11 (10.0.26200)。 测试先于生产修复执行: ```text bun test packages/shared/src/outcome/repository.test.ts packages/shared/src/outcome/service.test.ts → 19 pass / 4 fail ``` 四个失败覆盖并发观点保存、并发评估结果保存、两集合交错保存,以及真实 `OutcomeService.createOpinionFromReport()` 与 `evaluateDue()` 的重叠持久化。 ## 修复范围 按解析后的目标文件路径串行化两个保存方法的完整读改写。沿用 ConnectionStore 的进程内队列模式,兼容同一文件上的多个 store/repository 实例;失败对原调用方保持可见,且不阻塞后续更新。保持 JSON schema、读取行为和 upsert 语义。 范围限定于单个应用进程内的并发写入,不承诺多进程事务,也不恢复已经丢失的数据。 本报告与配套改动由 Codex 在用户授权下准备,未调用真实金融提供方。
Activity
huyengiang101086-spec commentedon Oct 12, 2026
/claim