63 lines
4.6 KiB
Markdown
63 lines
4.6 KiB
Markdown
# Codex rollout 历史合并修复计划
|
||
|
||
## 目标
|
||
|
||
让 cc-web 持久化消息成为当前会话的权威顺序;Codex native rollout 仅补充更早历史,按 turn 聚合助手输出,并通过稳定消息标识完成历史合并与前端去重。
|
||
|
||
## 合并契约
|
||
|
||
- 持久化快照中去掉 `ccwebPersistenceNotice` 后的消息保持原有顺序,是当前会话的权威尾部;native 只能补充快照之前的消息。
|
||
- 快照压缩时保存 `historySnapshotBaseIndex`(native 逻辑消息索引)与 `historySnapshotCount`,旧快照缺字段时按稳定 ID/最长公共后缀推断,无法确认边界时保留快照。
|
||
- 合并顺序固定为:native 更早消息 → cc-web 持久化消息 → 当前运行中的消息;相同稳定 ID 只保留 cc-web 消息,ID 冲突且内容不一致时以持久化消息为准并记录告警。
|
||
- native 缺失、解析异常、边界无法确认或合并结果不能证明快照尾部完整时,返回 cc-web 快照,不把未经确认的 native 消息插入当前视图。
|
||
- `session_info`、`resume_session_result`、`session_history_chunk` 均调用同一解析结果;分页只对该结果切片。
|
||
|
||
## 稳定标识契约
|
||
|
||
- 用户消息:优先 `clientMessageId`,兼容旧字段 `id`;缺失时生成并持久化 `client:<uuid>`。
|
||
- Codex App 助手消息:使用 `codexAppTurnKey`,其输入为 session/thread/turn 的稳定字段;旧消息缺失时从对应运行状态或时间戳生成一次并保存。
|
||
- native rollout 助手消息:使用 `nativeTurnKey`,由 threadId + turnId/turn_context 组成;同一 turn 跨刷新保持一致。
|
||
- 跨对话回传:保留 `replyToRequestId`(兼容 `crossConversation.replyRequestId`),同时生成 `reply:<requestId>` 作为稳定消息 ID;来源元数据始终保留。
|
||
- 其他历史消息按 `message:<role>:<timestamp>:<sha256(content)>` 降级,避免数组下标去重;ID 冲突时以权威来源和较完整内容决胜。
|
||
|
||
## Turn 聚合契约
|
||
|
||
- 以 `turn_id`、`turn_context.turn_id`、`turn_context.id` 或 session/thread 上下文组成 turn key;缺失时使用相邻事件窗口的稳定 fallback key。
|
||
- 同一 turn 内按 rollout 文件顺序合并文本片段、工具调用与工具结果;只有遇到下一条用户消息、turn 完成/失败事件或文件结束才 flush。
|
||
- tool call/result 绑定同一调用 ID;空 turn 不产出气泡;跨对话内部 user 回传不作为普通 user 消息插入。
|
||
|
||
## 前端契约
|
||
|
||
- 服务端先输出规范化消息序列;前端渲染层按 `message.id`/`messageId`/`nativeTurnKey`/`codexAppTurnKey`/`replyToRequestId` 形成稳定键。
|
||
- `renderMessages`、分页 prepend、`reconcileRenderedSessionMessages` 均按稳定键去重,索引仅用于定位/排序兼容;同键内容更新应替换原 DOM,不追加新气泡。
|
||
- 实时消息与历史消息竞态时,以服务端规范化消息为准,保留当前用户消息与对应助手回复邻接关系;跨对话回传显示来源标识,角色保持 assistant。
|
||
|
||
## 可验收测试矩阵
|
||
|
||
- 历史合并:无 native、无快照、完全重叠、native 仅更早、快照尾部用户消息、native 异常/边界不明回退快照;断言顺序、长度、稳定 ID。
|
||
- rollout 聚合:同一 turn 多个 message/tool/result 仅一条 assistant;下一用户消息 flush;turn 完成/失败 flush;内部回传不生成 user 气泡。
|
||
- 稳定 ID:重复加载/刷新/分页 ID 不变;clientMessageId、codexAppTurnKey、replyToRequestId 去重;冲突以持久化消息为准。
|
||
- 前端回归:session_info/resume/history chunk 重复到达不追加;实时流与历史同时到达不拆泡;来源标识和当前生成消息同时可见。
|
||
- 浏览器实测:重载运行会话时用户原问题、架构回复、子对话来源标识、当前生成消息均按逻辑顺序可见。
|
||
|
||
## 步骤
|
||
|
||
- [complete] 盘点服务端、rollout、持久化与前端消息链路
|
||
- [complete] 设计并实现稳定消息标识与 native 历史合并
|
||
- [complete] 聚合 Codex rollout 的同一轮助手输出
|
||
- [complete] 调整前端规范化历史渲染与稳定 ID 去重
|
||
- [complete] 增加历史合并和 rollout 聚合回归测试
|
||
- [complete] 运行静态检查、单测和浏览器/集成验证并收尾
|
||
|
||
## 约束与决策
|
||
|
||
- 保留工作区已有未提交改动,不覆盖 `lib/ccweb-mcp-server.js` 与 `scripts/ccweb-message-reply-unit.js`。
|
||
- 不把未确认的 native 消息插入当前 cc-web 快照;合并失败时返回快照。
|
||
- 回传消息保留来源标识,不能伪装成普通用户气泡。
|
||
- 所有可观测失败记录简短告警,不阻断当前会话展示。
|
||
|
||
## 错误记录
|
||
|
||
| 错误 | 尝试 | 处理 |
|
||
|---|---|---|
|