文件和行号
internal/tool/swarm_task_tools.go:367-383
问题描述
duplicate-complete 守卫是两步非原子:先 Get 检查 Status==Completed,再无条件 Update(UpdateOptions 只传 Status)。同文件 claim 路径(#861)已示范的 ExpectedStatus 条件更新原语在 complete 路径漏用。internal/task/manager.go 的 Manager.Update 整体在 m.mu 下执行且 ExpectedStatus 检查在锁内——原子 CAS 已存在但未使用。
触发场景
两个 teammate(stale 视图)并发调用 swarm_task_complete 同一 in_progress 任务:A/B 都通过 Get 检查(竞态窗口)→ A Update 成功 → B Update 也静默成功(completed→completed 无守卫,仅刷新 UpdatedAt)→ 双发 EmitBoardUpdated 事件。B 按注释声明语义("must not silently succeed")应失败但成功了。
预期行为 vs 实际行为
预期:并发 double-fire 第二次原子失败。实际:击穿守卫静默成功(无计数器损坏,仅语义矛盾+重复事件)。
修复建议
为 Update 增加 ExpectedStatus 多态支持(或新增锁内 CompleteIf 原语,允许 pending/in_progress 两态),complete 路径改用条件更新;顺带裁决"未 claim 的 Pending 任务可直接 complete"是否合法语义。
严重程度
low(独立复核确认:真实竞态窗口、修复原语就在同文件同族、无数据损坏副作用)
文件和行号
internal/tool/swarm_task_tools.go:367-383
问题描述
duplicate-complete 守卫是两步非原子:先 Get 检查 Status==Completed,再无条件 Update(UpdateOptions 只传 Status)。同文件 claim 路径(#861)已示范的 ExpectedStatus 条件更新原语在 complete 路径漏用。internal/task/manager.go 的 Manager.Update 整体在 m.mu 下执行且 ExpectedStatus 检查在锁内——原子 CAS 已存在但未使用。
触发场景
两个 teammate(stale 视图)并发调用 swarm_task_complete 同一 in_progress 任务:A/B 都通过 Get 检查(竞态窗口)→ A Update 成功 → B Update 也静默成功(completed→completed 无守卫,仅刷新 UpdatedAt)→ 双发 EmitBoardUpdated 事件。B 按注释声明语义("must not silently succeed")应失败但成功了。
预期行为 vs 实际行为
预期:并发 double-fire 第二次原子失败。实际:击穿守卫静默成功(无计数器损坏,仅语义矛盾+重复事件)。
修复建议
为 Update 增加 ExpectedStatus 多态支持(或新增锁内 CompleteIf 原语,允许 pending/in_progress 两态),complete 路径改用条件更新;顺带裁决"未 claim 的 Pending 任务可直接 complete"是否合法语义。
严重程度
low(独立复核确认:真实竞态窗口、修复原语就在同文件同族、无数据损坏副作用)