Skip to content

[bug] Agent 源扫描 Skill 层记忆因 createdAt 使用文件 mtime 导致幂等 409,「同步新增」永久报「扫描失败」 #369

Description

@Evason-yang

现象

桌面端「同步新增」(agent source scan)始终提示「扫描 Codex 失败,请稍后重试」,且永不自愈——每次扫描都失败,即使没有任何新对话。

日志(~/Library/Logs/Memmy/memory.log)中对应大量 409:

POST /api/v1/memory/add → 409 conflict
"idempotency key reused with different request body"

实测本地累计 287 条(9/4 起持续出现),key 全部是 memory.add:agent-source:codex:agent-source-skill:... 形态。

根因

Skill 层记忆写入的请求构造(App/backend/src/services/agent-source-service.tsscanSkills 内):

requestId: `agent-source-skill:${sourceId}:${skill.sourceSkillId}:${skill.sourceContentHash}`,
// ...
createdAt: skill.updatedAt,   // ← = SKILL.md 的文件 mtime(skill-distribution-service.ts: fileStat.mtime.toISOString())

服务端幂等校验(Memory/src/server/http.ts + memory-service.ts#idempotent):

  • key = operation:adapterId:requestId(requestId 含 contentHash,内容不变则 key 不变)
  • requestHash = sha256(整个请求体)
  • key 相同 + hash 不同 → 409

矛盾在于:requestId 承诺「内容指纹」,请求体却包含不受内容控制的 createdAt(文件 mtime)

触发场景(实测):Codex 更新时重写了 ~/.codex/skills/*/SKILL.md——内容完全相同(contentHash 不变),但 mtime 变了。下次扫描:

requestId 相同(内容没变)
请求体 createdAt = 新 mtime ≠ 存量 hash 时的旧 mtime
→ 同 key 不同 body → 409 → 扫描整体报错

实测证据:imagegen skill 的 contentHash 自 8/28 起未变(幂等表 8/28 已有该 hash 的记录),文件 mtime 却是 9/4 10:05(Codex 当天更新),9/4 起日志出现 162 条 409。

由于扫描会全量重试所有 skill,冲突键永不清理,错误永久存在

复现步骤

  1. 正常完成一次 Codex 扫描(skills 全部入库)
  2. touch ~/.codex/skills/<任意skill>/SKILL.md(不改内容)
  3. 桌面端点「同步新增」→ 扫描 Codex 失败;日志出现 409

修复建议

agent-source-service.ts 的 skill addMemory 请求移除 createdAt 字段(它是可选字段,服务端不传时用接收时间兜底)。移除后请求体完全由内容决定,与 requestId 语义一致:

  • 内容变 → contentHash 变 → 新 key → 正常入库
  • 内容不变 → 请求体完全相同 → duplicate: true,正常去重

已在本地验证完整修复链路(源码修改 + 清理冲突幂等键后,复刻扫描子进程全量跑:错误数 38 → 0,38 条消息正常去重跳过)。

附加建议(可选,双保险)

服务端 idempotent() 的 fingerprint 也可以考虑排除 createdAt 这类时间字段——mtime 语义上不该参与「同 key 不同 body」的判定。客户端修复已足够解决本 bug,此项供讨论。

环境

  • Memmy 桌面端 1.1.0(macOS arm64)
  • 扫描源:Codex(~/.codex/skills/,约 90 个 skill)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions