10 KiB
生产入库与失败路径只读审计
审计时间:2026-10-10 16:45—16:50(Asia/Shanghai)。
整改复核(2026-10-10):本报告保留的是修复前证据,下述七项独立缺口及 child 冲刷失败问题均已修复。history-runtime-unit.js 和 history-runtime-completion-unit.js 分别通过 13 项真实生产路径回归;后者还覆盖初次用户输入与 steer 保存失败阻断发送、跨会话返回失败保留重试、运行恢复幂等及子会话冲刷失败保留队列。详情见 runtime-test-result.md 与 completion-regression-result.md;不代表异机目标会话已恢复。
范围:当前 PRD、research/persistence-result.md、后端质量规范,以及 Claude/Codex CLI、Codex App、跨会话返回的生产保存路径。实现代理仍在改代码,下述行号对应审计时源码,整合前需再次核验。仅写本报告;未修改实现文件、真实会话、配置,未重启服务。
独立缺口
| 优先级 | 位置 | 触发场景与实际损失 | 建议行为回归 |
|---|---|---|---|
| P1 | server.js:9487、:9490、:9516 |
Claude/Codex CLI 回合只有工具,没有正文或 contentBlocks。完成分支条件不含 toolCalls,因此零入库后删除运行目录,正常成功的工具结果全部消失。恢复分支已接受纯工具,正常完成仍遗漏。 |
使用真实 handleProcessComplete,输入空正文和完整工具调用;归档读回全部调用与长结果,只有归档成功才删除运行目录。 |
| P1 | lib/agent-runtime.js:519、:530、server.js:9490 |
Codex CLI 同一回合先纯文本、再 JSON 内容块、最后纯文本。解析器把纯文本放 fullText,JSON 放 contentBlocks;完成保存选择 `contentBlocks |
|
| P1 | server.js:9699、:9702、:9707 |
Codex CLI 在服务停止期间完成含图片等非文本内容块的回合。恢复判断和正文仅用 tempEntry.fullText:仅图片时不保存且删除日志;文本加图片时成功保存正文但丢图片。 |
用隔离 JSONL 夹具覆盖仅图片、文本加图片、混合内容;真实 recoverProcesses 后读回完整内容块,保存失败时目录保留。 |
| P1 | lib/agent-runtime.js:420、:433、:458 |
Claude 流式输出以 type: "user"、message.content[].type: "tool_result" 返回工具结果。解析器只在 assistant 下处理 tool_result,没有 user 分支,最终工具仍 done: false 且无 result。正文成功保存也不能补回工具结果。 |
真实 processClaudeEvent 依次输入 assistant/tool_use、user/tool_result、assistant/text、result;从自身档案读回完整工具结果。保持用户消息与 runtime 工具结果的语义区别。 |
| P1 | server.js:12420、:12456、:12514;:14959、:14972 |
用户提问初次保存或 Codex App steer 用户消息保存返回 false,调用者仍启动任务/发送 turn/steer。若存储在助手完成前恢复,完成函数重新加载旧归档并成功保存助手,用户提问已经缺失;恢复输出 JSONL/完整 turn 状态不能保证包含原用户正文与附件。 |
第一次归档写失败、之后恢复可写;确认不会在未保存提问时启动/接受 runtime,或明确保留且补交相同用户消息。重开后用户目录包含原提问,重复提交不重复。 |
| P1 | server.js:8330、:8344 |
跨会话返回气泡保存失败被忽略,代码仍设 returned、删除待返回请求、返回 true,并可启动后续任务。源会话自身缺少返回气泡,请求队列也不再保留这次交付,用户看见的成功状态与保存结果不符。 |
注入源归档保存失败,待返回请求保持可重试状态且不能宣告已交付;恢复存储后重试一次,源完整档案恰好一个返回气泡,保留交叉会话元数据。 |
| P1 | 最新 server.js:9708、:9714、:9719、:9722 |
CLI 正文归档提交成功后、运行目录清理前崩溃,或清理本身失败。下次重启重复解析同一 JSONL,恢复消息没有 CLI turn 标识或提交去重检查,再追加同一完整正文。Codex App 已有 turnKey 去重,CLI 尚无。 | 原子提交成功后模拟清理失败,重开并重复恢复同一运行目录;归档始终恰好一次工具/正文记录,同时正常相同正文的不同回合不能被错误合并。 |
这七项独立于已经发现的 Codex App 完成前正文/工具裁剪、运行态裁剪和任务看板克隆后丢可信来源。
主线程优先要求的用户输入路径于 16:49 再次核验:最新
handleMessage 的 saveSession(session) 为 server.js:12432,
handleCodexAppSteerMessage 的 saveSession(currentSession) 为
server.js:14969,两者均忽略返回值并继续 runtime/steer。
这个分支应该先明确失败,避免出现“助手最终成功入库,但原用户提问缺失”。
次要失败观察
flushPendingCcwebMcpChildSession(server.js:13219)在保存前删除
pendingCcwebMcpChildSessionFlushes(:13223),末尾虽返回
saveSession(:13237),最终状态调用者和 timer 调用者不检查结果。
如果归档瞬时失败且后续没有新 child 事件,最后的工具协作状态不再自动重试。
建议把队列移除放到保存成功后,并用最终子线程事件加一次失败/成功冲刷回归。
这里主要损失父工具的最终展示状态;不能据此推断子会话自身完整档案已经丢失。
已出现的修复与不应重复取消的限额
- 当前运行时创建已传
preserveFullHistory: true;CLI 注入的truncateObj为恒等函数。先前 CLI 的 256 KiB 正文尾部保留、2,000 字符工具结果等生产裁剪已被本轮修改绕过。本报告不再将它们作为未修独立缺口。 - 当前
writeCodexAppTurnState先调用完整sessionHistoryStore.saveTurn,之后才写有界运行预览;加载优先完整 turn 状态,恢复内容不再二次裁剪,恢复归档保存失败提前返回并保留完整状态。完整 turn 档案枚举也已进入重启恢复。 - 当前 CLI 正文完成保存失败和 Codex App 完成保存失败已经显式报告
session_save_failed、historySaved: false并保留恢复材料,正常失败清理问题正在被修复。 - CLI 重启恢复已移除超过 16 MiB 就跳过输出并删除目录的分支,并在归档保存失败时
continue保留输出目录。 sendRuntimePreview、会话传输、标题摘要、MCP 参数校验、文件预览是独立用途的有界数据。只要未把其结果回写唯一完整正文/工具内容,不需要取消这些限额。loadCodexAppTurnState仍对旧版有界状态设置加载限制。新增完整 turn 来源已优先读取;旧文件异常处理与完整档案损坏恢复应单独判断,不宜为解决新记录完整保存直接删除所有异常防护。- 检索未发现除主线程已通知的任务看板适配器以外的明显
cloneJson/JSON.parse(JSON.stringify(...))后调用统一保存的生产入口;一般标题、模式、usage、MCP 状态等保存返回值忽略主要影响元数据确认,不等同于本报告的唯一内容清理路径。
隔离证据
在 timeout 60s node 中通过 vm.runInNewContext 提取生产完成、恢复、跨会话返回和 child 冲刷函数,结合真实 createAgentRuntime。所有 fs、WebSocket、队列和保存均为内存桩;没有真实会话写入。
前三组命令分别约 0.03 秒、0.05 秒和 0.03 秒,退出码 0,断言证实:
- CLI 纯工具回合零次保存、一次目录清理。
- Codex CLI 混合内容成功保存丢前后纯文本。
- 仅图片内容块的 CLI 重启恢复零次保存、一次目录删除。
- Claude user/tool_result 解析后工具仍未完成且结果为空。
- 跨会话源保存返回 false 时,交付函数仍返回 true 且队列请求被删除。
- Child 最终状态冲刷保存失败,待冲刷队列仍被删除。
- CLI 恢复保存再次失败时不会清理 pending 输出;存储恢复后可成功提交。
- CLI 成功提交后模拟清理失败,再执行恢复会产生两条相同助手消息。
用户提问与 steer 保存失败项通过生产控制流确认,尚未执行其大依赖入口的完整行为夹具。Claude 的协议场景采用合成标准事件验证解析器;未读取本机或异机真实 runtime 日志,本报告不宣称异机实测已完成。
完成失败后的 pending 恢复结论:CLI 路径已经符合“保存失败明确失败且保留运行输出”的行为,后续存储恢复可重新归档;未修缺口是恢复内容块与提交后幂等性。Codex App 通过完整 turn 档案、失败时保留、恢复时检查 codexAppTurnKey 的静态链路已经覆盖同类条件,本子审计未再发现另一个正常完成后清理唯一完整 turn 内容的独立分支。磁盘持续不可写时只能如实报告失败,本报告不把物理无法提交误判为成功保存。
工具调用简报
- 时间:2026-10-10 16:35—16:50,Asia/Shanghai。
codebase-memory-mcp:list_projects与index_status(home-cc-web)返回 ready;search_code收敛server.js的saveSession,search_graph/get_code_snippet定位 CLI 完成/恢复、运行事件和 Codex App 状态函数。本子线程服务可用,没有重启或重建索引。- FastCtx
glob/inspect_local_file:扫描可用技能与按指定路径读取 PRD、保存报告、质量规范和生产局部源码。个人技能中无必要匹配的只读失败审计技能。 - 本地
rg/局部sed:交叉核验修改中的最新源码与行号。实时修改已使部分 codebase-memory 片段落后,结论以最终局部源码和隔离生产函数证据为准。 - Node VM:只读源码加内存桩验证六个失败场景;每次总超时 60 秒;无外部请求,无敏感内容输出。