现象(Symptoms)
- 对 Agent 源 Codex 执行扫描,界面一直报「扫描失败」。
- memory.log 每次扫描出现 6~12 条:
"statusCode":409,"error":"conflict","message":"idempotency key reused with different request body"
- 扫描源水位(latest_seen_created_at)永久停在失败前的值,不再推进;之后每次重扫必失败(死循环)。
- 手动把水位推进到「最新」可临时恢复一次;但 Codex 对已导入过的会话文件再次改写,下一轮扫描立刻复发。
环境(Environment)
- Memmy 桌面端 1.1.1(Windows x64;最新 v1.1.2 未见修复,main 分支亦未修复)
- 扫描源:Codex(builtin),数据目录 C:\Users\user.codex\sessions(JSONL rollout)
- 复现会话:rollout-2026-09-07T00-54-21-01a077a4-….jsonl(约 8.4MB,消息 >1100 条)
复现步骤(Steps to reproduce)
- 用 Codex 开启长会话并持续使用数小时。
- Memmy 首次增量扫描成功导入部分消息(实例:导入至消息 :964,checkpoint 07:18:50Z)。
- Codex 继续使用/对该 rollout 文件重编码改写(mtime 更新、已导入消息正文序列化变化、追加新消息)。
- 再次触发「扫描 Codex」。
- 失败:扫描器判定会话「内容修订」整场重放,已导入的同一消息 ID 以不同正文重新提交 → memory/add 幂等层拒绝 → 409 → 扫描整体失败。
预期行为(Expected)
- 增量扫描应正确处理「会话文件被改写」:按 checkpoint 增量跳过已导入部分只导新增;或以更新语义重放(更新既有记忆)而非冲突失败。
- 个别消息冲突不应导致整场失败、水位永不推进(避免永久死循环)。
实际行为(Actual)
- 扫描器检测内容修订后整场重放全部消息(含已导入同一 messageId),memory/add 返回 409,扫描报错。
- agent-source-service 水位仅在整场零错误时推进,一条 409 即永久卡死 → 每小时/每次手动扫描重复失败。
- 用户只能手工改库推进水位临时跳过,代价是该会话历史不再进入记忆。
根因分析(Root cause)
- Codex 会重写/重编码已导入的会话文件:同一 messageId 的正文序列化发生变化(实证:成功导入后文件被改写,mtime 更新、内容哈希变化)。
- 扫描器对「内容修订」会话整场重放:findContentRevisedConversationIds() 判定「最新消息游标==checkpoint 但 content_hash 不同」→ replaySeenConversationIds 整场重放。
- 内存服务幂等层恰好拒绝该重放:memory-service.ts 中 idempotent() 以 key=operation:adapterId:requestId、requestHash=stableHash({operation,fingerprint}) 判重,同 key 不同指纹直接抛 409。
即:扫描器主动检测并重放「内容修订」会话,但 memory/add 幂等层恰恰禁止「同 key 换正文」——重放路径架构上永远走不通;再叠加「水位只在零错误时推进」,形成永久死循环。
影响(Impact)
- 任何「已导入过、之后又被 Codex 改写」的会话都会让 Codex 源扫描永久失败。
- Codex 是活跃使用的 Agent,长会话重编码是常态,高频复发(本机 09-06~09-08 连续三天,数十次 409)。
- 用户无法通过界面恢复,只能手工改库推进水位(有数据丢失风险)。
相关 issue(Related)
附:关键代码位置(main,2026-09-08 仍未修复)
- Memory/src/service/memory-service.ts → idempotent()
- App/backend/src/services/agent-source-service.ts → findContentRevisedConversationIds() + replaySeenConversationIds;水位仅 input.final && stats.errors.length===0 时推进
- App/backend/src/adapters/outbound/agent-source/codex/adapter.ts + conversation-window.ts → 整场会话窗口语义
现象(Symptoms)
"statusCode":409,"error":"conflict","message":"idempotency key reused with different request body"环境(Environment)
复现步骤(Steps to reproduce)
预期行为(Expected)
实际行为(Actual)
根因分析(Root cause)
即:扫描器主动检测并重放「内容修订」会话,但 memory/add 幂等层恰恰禁止「同 key 换正文」——重放路径架构上永远走不通;再叠加「水位只在零错误时推进」,形成永久死循环。
影响(Impact)
相关 issue(Related)
附:关键代码位置(main,2026-09-08 仍未修复)