Files
cc-web/.trellis/tasks/10-10-snapshot-history-pagination/research/failure-audit.md
shiyue 69b6db0f5b 修复完整会话历史与长气泡交互并更新 CentOS 7 发布包
提交当前工作区全部源码、回归脚本、任务记录及重新构建的 Bun baseline 发布包。发布单文件 MCP 初始化及前端资源一致性验证通过。
2026-10-10 23:40:16 +08:00

74 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 生产入库与失败路径只读审计
审计时间: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 || fullText`,成功归档只保留中间内容块,丢前后正文。 | 真实解析器依次输入三类 `item.completed`,再用真实完成函数保存,重开完整档案后确认前文、内容块、末尾及顺序均存在。 |
| 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,断言证实:
1. CLI 纯工具回合零次保存、一次目录清理。
2. Codex CLI 混合内容成功保存丢前后纯文本。
3. 仅图片内容块的 CLI 重启恢复零次保存、一次目录删除。
4. Claude user/tool_result 解析后工具仍未完成且结果为空。
5. 跨会话源保存返回 false 时,交付函数仍返回 true 且队列请求被删除。
6. Child 最终状态冲刷保存失败,待冲刷队列仍被删除。
7. CLI 恢复保存再次失败时不会清理 pending 输出;存储恢复后可成功提交。
8. 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 秒;无外部请求,无敏感内容输出。