4.6 KiB
R9 任务报告:post-task 去重串线取消事故
结论
本次事故不是 AgentRun 自动控制器执行 sibling task reconcile,也不是后端按投影自动取消。
事故由两段 UniDesk 受控流程缺陷串联产生:
- Artificer Target create 的 idempotency key 未绑定最终 prompt/payload,且显式
--idempotency-key可以绕过 canonical identity; - 外部 post-task 收尾操作按一次 dispatch 归组,并用相同 reason 人为取消三个不同 logical operation。
引入提交为 43124d01。该提交建立 Target 只读预检、完整位置上下文和自动 dispatch,整体方向符合当前规格;本次属于局部幂等实现缺陷,不满足整 PR 方向错误的语义回滚条件,因此没有回滚整个提交。
离线证据
三个被误取消 task:
qt_d214e48f4b0d4d6e899428e2855121ac:payload hash 为e7c8bb1016fad9a2e27fb69b20c9c5c069fe13fb1632edf8c604c3a5ad79c3c3;qt_7c12fa9735634934a64986a1d45cfc44:payload hash 为b48d75f1d717ff36d640f67b28a44c1f016183b677680e727c3ac27a1aa1e206;qt_45e692244cbd42a9aa28cc9706f4a28f:payload hash 为bccec985937e047e95b1fed23da15927f60f14d3ac36c58ac7101329487572b6。
三者在 2026-07-15 09:19:03–09:19:42 UTC 进入 cancelled,failure message 完全相同:
duplicate create task from one post-task dispatch; preserve qt_c94a19c6bd824551bcb7b22a51c266af
被保留的 qt_c94a19c6bd824551bcb7b22a51c266af payload hash 为 7904461ada875b99d79c4a98a0d82ba7b75bffa3e4c2524ebcb1f3e2ac2cc15f,属于 Issue #1888。该 task 随后在 2026-07-15 09:22:16 UTC 以“请求 #2170 却复用旧 #1888 input”原因取消,证明 create 幂等复用已经先发生串线。
仓库源码与 Git 历史中不存在上述 duplicate reason,也不存在按 post-task dispatch 自动扫描和取消 sibling task 的 controller。AgentRun session 事件还证明 #1888 session 自身只取消了它刚误创建且尚无 attempt 的嵌套副本,没有执行本次三项取消。
修复
scripts/src/agentrun/target-task.ts 现在生成版本化 canonical logical-operation fingerprint,绑定:
- tenant/project;
- Aipod;
- MDTODO;
- Target;
- repository/ref;
- 绝对 targetWorkspace;
- 已核验源码提交;
- 最终 prompt 的 SHA-256 payload hash。
同一 operation 重放生成相同 key;任一 scope 或 payload 变化都会生成不同 key。
Target create 收到显式 --idempotency-key 时,只接受与 canonical key 完全一致的值。不同 payload 复用旧 key 会在 render 和 queue mutation 前返回:
- stage:
idempotency-key-conflict; - code:
target-task-idempotency-key-conflict; - reason:
provided-key-does-not-match-canonical-logical-operation; - canonical fingerprint;
- payload hash;
- provided key 的不可逆 fingerprint;
mutation=false与valuesPrinted=false。
task metadata、dry-run 和 mutation 摘要保留 logical-operation evidence,供事件和 OTel 投影读取,不打印 prompt 或 Secret。
unidesk-subagent skill 同步明确:
- 禁止按 dispatch、时间窗口、session、标题或列表邻近关系判定重复;
- identity 不全、投影陈旧或终态不确定时只 warning;
- post-task cleanup 不得取消 sibling task;
- 取消只用于用户明确授权目标或同一 task/attempt 的受控终止。
验证
Target 原入口轻量验证:
git diff --check
bun test scripts/src/agentrun.test.ts --test-name-pattern 'Artificer Target'
结果:4 个测试通过,0 失败,72 个断言。fixture 覆盖 R8、R7.1、R7.2 与 #1888 四个不同 logical operation,并验证:
- 四个 key 全部不同;
- 同一请求重放 key 稳定;
- prompt 变化会改变 key;
- 显式旧 key 与新 payload 冲突时返回 typed evidence,且不披露原 key。
OTel 证据边界
事故时间窗的 Tempo 搜索没有找到 queue task cancel HTTP route、task ID 或 cancel reason span。当前 AgentRun durable attempt terminal fact 可证明取消结果和 reason,但不能从 OTel 单独恢复取消调用者。
调查 trace 01fb780dc5184363fea5f8ef859c9031 仅覆盖本次 R9 只读调查命令,不作为事故调用者证据。修复后的 logical-operation evidence 已进入 task metadata;PR 自动交付后应从新的正常 create/replay 原入口确认对应 span/event 投影。
本任务没有新增锁、租约、第二状态库、数据库迁移或运行面围栏;没有取消任何现存 task,没有执行 runtime patch、人工 CI/CD 或 PR merge。
关联:UniDesk #2176,MDTODO R9。