4.7 KiB
完整历史持久化实现记录
日期:2026-10-10。负责范围:服务端完整归档、保存入口与生命周期、专项回归。
失败回归证据
先新增 scripts/session-history-store-unit.js,使用生产保存、裁剪、读取、resolver 函数及临时文件系统。原生日志测试通过真实 JSONL 文件和生产 createCodexRolloutStore 解析,未使用消息数组 mock 替代读取。
旧实现运行 timeout 60s node scripts/session-history-store-unit.js 退出码 1,9 项失败、2 项通过,约 1.2 秒:
- 650 条保存后重开只读回最后 180 条及提示;快照上限调为 500 仍损失 150 条。
- 长正文、125 条工具调用、工具参数/结果、长数组和深层元数据未完整保存。
- 受限短预览再次保存被接受,旧修订也可覆盖后来已提交的追加。
- 完整档案不存在,原子归档失败保护和缓存失败提交语义不成立。
- 真实 rollout 确认前缀后 resolver 仅在内存合并,没有建立自身档案。
完整原始输出在临时日志 /tmp/ccweb-persistence-before.txt;本文件记录可审计结论,未写入任何真实会话或配置。
已确定设计
- 新增
lib/session-history-store.js,sessions/_history/<id>.json为完整会话的原子提交点。 - 归档保存完整 JSON 数据,排除既有运行态句柄,不进入消息/正文/工具/数组预览裁剪。
- 可信加载来源与归档修订使用内存身份信息,root 快照或任意短预览不能伪造完整加载。
- 可信当前修订精确替换消息数组;可信旧修订基于加载基线合并本次变更,保留后来已提交的追加和元数据,冲突字段保留已提交值。未经可信加载的短预览拒绝覆盖档案。
- 完整归档成功、快照失败视作已提交;
loadSession无 root JSON 仍优先读归档,列表接入归档孤儿缓存修复。 - 旧截断状态继续保留。只有现有边界规则确认原生前缀后,才把补齐结果提交档案。
实现与验证
核心模块与 saveSession / loadSession 接入已完成;统一生命周期已覆盖:
resolveSessionHistory使用既有边界规则确认后先提交归档,提交失败只返回原快照。loadSession即使 root JSON 缺失仍读取归档;列表枚举孤立档案,按归档修订修复有界缓存,缓存继续失败时使用内存有界预览展示。- 导入统一先读取可信档案;已有会话只有可靠边界确认后才补前缀,保留 cc-web 专有气泡和顺序。
/clear建立新的清空修订,旧运行对象不能复活原线程历史或返回输出;删除会话同步删除自身档案。- 迁移保留原始快照备份,使用统一完整归档入口,不再直接写无界 root JSON。
当前专项检查:
timeout 60s node scripts/session-history-store-unit.js:完整持久化回归 21 项通过。timeout 60s node scripts/session-history-unit.js:原服务端历史回归 12 项通过。timeout 60s node scripts/history-frontend-unit.js:前端历史分页、目录索引、认证隔离和重试通过。timeout 60s node scripts/history-runtime-unit.js:生产 runtime 完整采集 13/13 通过,覆盖长正文、纯文本/结构块混合、纯工具、Claude tool_result、Codex App 工具数组及有界传输。timeout 60s node scripts/history-runtime-completion-unit.js:完成、恢复及保存失败生产路径 13/13 通过,已接入全量回归。包含真实保存失败注入、保留唯一运行输出、存储恢复后恰好提交一次、跨会话与 child 冲刷重试,以及任务看板 650 条历史保持完整;详情见completion-regression-result.md。npm run regression:Regression checks passed。- 隔离 Firefox 归档重启验收:
historySource=archive、148 条消息、6 个分页块、下标连续且无重复;原始日志夹具移开后仍可读。
生产路径补充保护:普通纯文本 CLI 回合保留字符串内容形状;结构化或混合回合才使用内容块数组;初次用户消息、steer、跨会话回传均在保存成功后才继续;CLI/Codex App 恢复在会话读取或归档保存失败时保留运行目录和完整运行态,避免清理唯一可恢复记录;CLI 使用 runKey 防止清理失败后的重复入库。
旧版本对照:timeout 60s node scripts/history-runtime-unit.js --baseline-head 复现预期的 9 项历史缺陷,证明专项断言确实覆盖原问题。核心文件 Node 语法检查与 git diff --check 通过。
边界:以上均为隔离临时目录、夹具或本地回归;未读取或修改用户在另一客户端看到的真实会话,未重启生产服务,不能据此声称那 45 条旧消息已经找回。