用户于 2026-08-29 发现 CG-27 第一次采购失败后,在 Agent 点击“重试采购”,任务主状态变成“待执行”但不再进入 PDD。用户确认重试采购应复用当前采购任务,只新增执行 attempt,不创建新采购任务,并要求新建缺陷工单修复。
lease_version
Start
start_request_id
rule_snapshot_hash
purchase_task.rule_snapshot
Reset
DefaultLiveRule()
purchase_task
Claim → Start
RuleSnapshot
恢复既有服务端状态机行为,无 UI/页面结构变化,按规则免原型。
预期无长期文档影响:同任务重试与失败可见性规则已在 Wiki 中记录,本单恢复已确认行为。若实施导致长期契约变化,再更新对应 Wiki。
代码修复已完成并推送 main,提交:8afbdbc。
main
8afbdbc
failed
PURCHASE_STATE_CONFLICT
go test ./app/goauto/purchase -run 'TestPurchase(Reset|Start)' -count=1
go test ./app/goauto/purchase -count=1
.\scripts\verify.ps1 -Component server
go test ./...
go build
python dev_scripts/harness.py check --strict
Next
无长期文档影响:未新增 API 字段或错误码,使用既有 PURCHASE_STATE_CONFLICT;同任务重试与失败可见性规则未变化,因此按规则跳过 Wiki 更新与同步。
下一步需用户明确授权:重启 Admin API,并把 CG-27 第 2 次 attempt 与主任务安全收敛为失败、清理租约/运行占位。修复后由用户自行点击“重试采购”生成同任务第 3 次 attempt;该操作可能进入正式采购并创建订单。
Gitea MCP 当前会话不可用,本工单创建与回写回退 Gitea API;凭据未输出、未落盘。
用户已明确授权:重启 Admin API,并将 CG-27 第 2 次 attempt 和主任务安全收敛为失败、清理租约及运行占位。
pending
result_request_id
irreversible_at
order_submit_request_id
pdd_order_no
order_submitted_at
使用带完整前置条件的单条 MySQL 多表更新,原子修改 purchase_task.id=27 与 purchase_task_attempt.id=28, attempt_number=2;受影响行数为 2:
purchase_task.id=27
purchase_task_attempt.id=28, attempt_number=2
lease_expires_at
claim_request_id
active_slot
device_run_slot
account_run_slot
goauto-admin-api
Running
curl --noproxy '*' http://127.0.0.1:8010/api/v1/health
请用户在 Agent 刷新 CG-27 详情,确认状态为“采购失败”且可以点击“重试采购”。再次点击会在同一 CG-27 下创建第 3 次 attempt,并可能进入正式采购、修改地址及创建待付款订单;必须由用户主动操作,系统永久禁止支付。
用户于 2026-08-29 明确确认本工单通过验收。验收结论已记录,现关闭工单。没有新的长期事实变化,本次不重复同步 Wiki。
No dependencies set.
The note is not visible to the blocked user.
原始需求摘要
用户于 2026-08-29 发现 CG-27 第一次采购失败后,在 Agent 点击“重试采购”,任务主状态变成“待执行”但不再进入 PDD。用户确认重试采购应复用当前采购任务,只新增执行 attempt,不创建新采购任务,并要求新建缺陷工单修复。
当前事实与根因
lease_version持续增加,但Start前 attempt 始终没有start_request_id。rule_snapshot_hash与数据库中purchase_task.rule_snapshot的实际哈希不一致。Reset对保存前的DefaultLiveRule()原始字节计算哈希;MySQL JSON 列保存后会规范化表示;Start对数据库读回值重新计算哈希,因此返回“待执行 attempt 与当前任务不一致”。目标
purchase_task,只新增 attempt。Start一致。Claim → Start对重试 attempt 可正常进入 running。非目标
依赖与并行
实施方案
Reset保存任务规则后,通过同一事务重新读取持久化任务,再以读回的RuleSnapshot计算 attempt 哈希。Reset与Start使用,避免计算口径漂移。Start检测 pending attempt 的设备或规则哈希不一致时,在事务内把 attempt 标记为 failed、写入稳定错误码/限长信息,同时把任务置为 failed、清理 lease、claim、device/account run slot;提交失败事实后返回可识别错误,不能因返回错误导致事务回滚。验收标准
purchase_task。Claim → Start成功后任务和最新 attempt 均为 running。风险与安全
设计证据
恢复既有服务端状态机行为,无 UI/页面结构变化,按规则免原型。
文档影响
预期无长期文档影响:同任务重试与失败可见性规则已在 Wiki 中记录,本单恢复已确认行为。若实施导致长期契约变化,再更新对应 Wiki。
实施完成,等待高风险步骤授权
代码修复已完成并推送
main,提交:8afbdbc。实现
Reset保存最新正式采购规则后,在同一事务重新读取数据库持久化后的purchase_task,再按读回的RuleSnapshot生成 pending attempt 哈希;不再对 MySQL JSON 规范化前的原始字节计算哈希。Reset与Start复用同一规则快照哈希函数,避免计算口径漂移。Start若发现 pending attempt 的设备或规则哈希与任务不一致,会在同一事务把 attempt 与任务标记为failed,写入既有PURCHASE_STATE_CONFLICT和明确错误信息,并清理 lease、claim、device/account run slot;事务提交后再向 Agent 返回错误,避免错误返回导致失败事实回滚。purchase_task,只新增 attempt,不修改商品、规格、数量、价格和地址快照。验证
go test ./app/goauto/purchase -run 'TestPurchase(Reset|Start)' -count=1:通过。go test ./app/goauto/purchase -count=1:通过。.\scripts\verify.ps1 -Component server:通过(go test ./...与go build)。python dev_scripts/harness.py check --strict:通过。Claim → Start正常进入 running;人为制造哈希不一致时任务/attempt 明确失败、租约和占位清空、Next不再重复派发。文档影响
无长期文档影响:未新增 API 字段或错误码,使用既有
PURCHASE_STATE_CONFLICT;同任务重试与失败可见性规则未变化,因此按规则跳过 Wiki 更新与同步。尚未执行
下一步需用户明确授权:重启 Admin API,并把 CG-27 第 2 次 attempt 与主任务安全收敛为失败、清理租约/运行占位。修复后由用户自行点击“重试采购”生成同任务第 3 次 attempt;该操作可能进入正式采购并创建订单。
Gitea MCP 当前会话不可用,本工单创建与回写回退 Gitea API;凭据未输出、未落盘。
已执行授权的重启与 CG-27 状态修复
用户已明确授权:重启 Admin API,并将 CG-27 第 2 次 attempt 和主任务安全收敛为失败、清理租约及运行占位。
执行前门禁
pending;第 2 次 attempt:pending,尚无start_request_id/result_request_id。irreversible_at、order_submit_request_id、pdd_order_no、order_submitted_at均为空,确认未进入创建订单不可逆边界。数据修复
使用带完整前置条件的单条 MySQL 多表更新,原子修改
purchase_task.id=27与purchase_task_attempt.id=28, attempt_number=2;受影响行数为 2:failed。PURCHASE_STATE_CONFLICT与“采购规则快照校验失败,请重新重试任务”。lease_expires_at、claim_request_id、active_slot、device_run_slot、account_run_slot。服务验证
8afbdbc启动goauto-admin-api。Running。curl --noproxy '*' http://127.0.0.1:8010/api/v1/health返回 HTTP 200。本机设置了 HTTP 代理,未绕过代理时的“响应提前结束”不是 API 故障。failed,第 2 次 attempt 保持failed,租约、领取标记与三个占位均为 cleared,未被 Agent 再次派发。后续验收
请用户在 Agent 刷新 CG-27 详情,确认状态为“采购失败”且可以点击“重试采购”。再次点击会在同一 CG-27 下创建第 3 次 attempt,并可能进入正式采购、修改地址及创建待付款订单;必须由用户主动操作,系统永久禁止支付。
用户于 2026-08-29 明确确认本工单通过验收。验收结论已记录,现关闭工单。没有新的长期事实变化,本次不重复同步 Wiki。