feat: 完善采购任务安全恢复 (#73)

This commit is contained in:
chengma
2026-08-10 00:27:52 +08:00
parent d6339a810f
commit c86c7482d9
15 changed files with 786 additions and 12 deletions
+8 -3
View File
@@ -340,9 +340,12 @@ Admin 侧必须无条件接受,见 [04](04-admin-api-contract.md) §6.1。
### 采购崩溃恢复
- 在最终提交订单前写入不可逆阶段标记。
- 如果进程在该阶段退出,重启后进入订单核对流程。
- 核对不到订单时进入人工处理,禁止自动重新下单。
- 每个采购关键动作前,先在同一 SQLite 事务中更新任务和执行记录的步骤。
- 演练运行中断且没有不可逆标记时,原执行记录先结束为失败,任务再回到
`claimed`;恢复执行必须创建新的 `attempt_id`,不会存在两条并发运行。
- `irreversible_action_at` 有值时,启动恢复立即转为 `manual_review / reconcile_purchase`。
`PurchaseReconcileService` 只能调用独立的只读 Adapter,不会调用采购 Adapter。
- 核对到唯一候选也仍需人工最终确认;未找到、多候选或结果不确定均保持人工处理。
- Admin 提交失败只重试 Outbox,不再次操作拼多多。
## 9. PDD 适配边界
@@ -359,6 +362,8 @@ reconcile_purchase(task, run) -> PurchaseResult | ManualReview
打开商品、读取状态、精确选择动态规格、设置数量、进入提交前确认页和停止,
**不提供提交订单或付款方法**。这样即使应用层调用错误,也没有可误触的真实下单入口。
采购规格使用完整 `options` 对象精确比较,不假定只有颜色和尺码两个维度。
只读核对另用 `PddPurchaseReconcileAdapter`,只暴露 `read_order_match`
和 `close`,不暴露选规格、设数量、下单或付款方法。
现有 `wait_goods_page`、规格面板坐标、颜色尺码选择和下单按钮定位函数可以迁移到该适配层。实验脚本中的硬编码商品、设备、文件路径和 `print` 不得进入正式服务。
+6 -2
View File
@@ -451,14 +451,18 @@ CREATE TABLE app_settings (
| 重启时发现 | 怎么处理 |
|---|---|
| `status = 'running'`,且 `task_runs.irreversible_action_at` **为空** | 说明还没下单,改成 `retry_wait`,正常重试 |
| `status = 'running'`,且 `irreversible_action_at` **不为空** | 说明可能已经下单了。**保持 `running`**,把 `current_step` 改成 `reconcile_order` 去核对订单。核对不到就转 `manual_review`。**任何情况下都不许重新下单** |
| 采集 `status = 'running'` | 改成 `retry_wait`,原执行记录结束为失败 |
| 采购 `status = 'running'`,且 `task_runs.irreversible_action_at` **为空** | 原执行记录先结束为失败,任务改回 `claimed / purchase_recovery_ready`;再次演练必须新建执行记录 |
| 采购 `status = 'running'`,且 `irreversible_action_at` **不为空** | 原执行记录和任务都改成 `manual_review / reconcile_purchase`;只调用只读核对,**任何情况下都不许重新下单** |
| `status = 'claimed'` | 说明领到了还没开始动手,保持不变,等协调器重新调度执行。**不需要再向 Admin 领一次** |
| `status = 'result_pending'` | 不动状态,交给 Outbox 继续重试提交 |
| `outbox_events.status = 'sending'` | 改回 `pending`,让它能被重新发送 |
一句话记住:**`irreversible_action_at` 有值 = 只准查,不准买。**
可重试的设备错误在采购演练中也先进入 `manual_review`,不会因为技术上
“可重试”就隐式重跑采购。这与采集任务的 `retry_wait` 规则不同。
## 8. `pdd_data` JSON
### 8.1 通用商品数据
+2
View File
@@ -202,6 +202,8 @@ class TaskTableModel(QAbstractTableModel):
当前 Client 使用可调整大小的非模态详情窗口。用户可以点击表格“详情”、双击任务行,或选中任务后按 Enter 打开。相同任务只保留一个详情窗口;再次打开时切回已有窗口。按 Esc 或“关闭”按钮返回任务列表。
详情面向采购人员,任务类型、状态、当前步骤和错误说明优先使用中文。数据库中的 `current_step` 等内部值只用于业务判断和日志,不直接显示;遇到尚未适配的新步骤时显示“未知步骤”。
采购演练和恢复至少要明确显示“演练已在提交前停止”、“结果待提交”、
“只允许核对订单”和“需要人工处理”;不能只用颜色表达安全状态。
采集规格按下面顺序展示:
+14
View File
@@ -82,6 +82,20 @@ PDD 解析测试优先使用脱敏的 XML 固件,不要求每次连接真实
8. 操作人员明确确认真实下单范围和安全设置。
真实下单不得通过调试参数、默认配置或界面误操作意外开启。
当前版本的 `ClaimCapabilities` 仅接受 `purchase_mode=dry_run`,采购
Adapter 不提供提交订单或付款方法。开发者不能把自动化测试通过当成真实
下单门禁放行;仍需项目负责人和实际操作人员共同确认。
### 3.1 当前自动化安全检查
- 关键手机动作前已持久化 `current_step`。
- 无不可逆标记的中断会先关闭旧运行,新运行使用新 `attempt_id`。
- 有不可逆标记的中断只调用只读核对,采购 Adapter 调用次数为 0。
- 已落库 Outbox 只补交,不重跑手机流程。
- 停止、设备断开、验证码、登录失效和结果不确定都保留稳定错误和诊断。
- `purchase_mode=live` 会在数据对象创建时被拒绝。
上述只证明演练和恢复代码的默认安全性,**不代表真实下单已放行**。
## 4. 自动化防护