完善采购任务崩溃恢复与安全门禁验证 #73

Closed
opened 2026-08-09 23:25:31 +08:00 by ila · 3 comments
Owner

基本信息

  • 类型:需求
  • 父级大工单:#1
  • 所属 MVP / 版本:#2 Client 可运行任务闭环(MVP)
  • 阶段:5. 采购演练与恢复
  • 依赖:#71、#72
  • 状态:待实施

要解决什么

采购演练可以执行和领取后,还必须验证崩溃、重复启动、结果提交失败和不可逆阶段恢复规则。虽然 MVP 不真实下单,但状态机和恢复路径必须先按真实安全边界建立,否则以后开启安全门禁时可能在进程崩溃后重复创建订单。

做什么 / 不做什么

做

  • 完善采购 task_runs 步骤持久化和恢复判定,关键步骤进入前先提交 SQLite。
  • 启动时检查未结束采购运行:未进入不可逆阶段的演练任务按明确规则恢复或失败;已存在 irreversible_action_at 的任务只进入订单核对/人工处理,绝不重新下单。
  • 同一稳定任务 ID 和执行记录避免重复运行;Outbox 未发送时只补交结果,不重复执行采购。
  • 实现 reconcile_purchase 的安全骨架:只读取、核对和记录结果,不点击下单或付款。
  • 覆盖停止请求、设备断开、Client 重启、Admin 暂不可用、重复启动和结果不确定等场景。
  • 界面用中文显示“演练完成、结果待提交、仅核对、需人工处理”等明确状态。
  • 建立真实下单安全门禁自动化检查清单;本工单只验证,不放行 live。
  • 更新质量、安全、数据模型和界面基线。

不做

  • 不打开真实下单开关,不点击提交订单,不付款。
  • 不绕过验证码、登录或风控。
  • 不自动清理已完成任务、执行历史和 Outbox。
  • 不允许采购任务从“重新执行”入口启动。
  • 不自行宣布真实下单安全门禁通过;最终放行必须由项目负责人和操作人员共同确认。

已确认的实现方案

  • 恢复决策只依赖 SQLite 已提交事实,不依赖内存标志或 Admin 当前状态。
  • 所有可能通向不可逆动作的步骤先写 current_step;真实版本进入不可逆阶段前必须先写 irreversible_action_at。
  • 恢复协调器按任务类型和运行事实分支:采集沿用原逻辑;采购一旦有不可逆标记,只调用只读核对接口。
  • 演练模式不会写不可逆时间,但测试需要构造该历史状态,证明恢复代码绝不会调用 purchase。
  • Outbox 与执行解耦:有未发送结果时先提交,不重新访问 PDD 页面。
  • 使用可注入 Adapter/时钟/故障点覆盖“每一步后崩溃”的确定性测试。

预计修改:采购任务服务、恢复协调器、Repository 状态查询、只读核对 Adapter 接口、事件/UI 状态、质量安全测试和 Client 基线文档。

验收标准

  • 采购每个关键步骤进入前已经持久化,进程退出后能识别最后可靠步骤。
  • 未进入不可逆阶段的演练运行按既定规则恢复,不产生第二条并发运行。
  • irreversible_action_at 非空时只调用订单核对,任何路径都不会再次调用采购/下单。
  • 结果已落 SQLite 但 Outbox 未发送时,只重试提交,不重新执行采购。
  • 重复点击、自动获取重启和 Client 重启不会重复处理同一进行中采购任务。
  • 停止、设备断开、验证码、登录失效和结果不确定会进入安全状态并保留诊断信息。
  • 采购任务继续禁止“重新执行”。
  • 界面状态和错误不只靠颜色,明确告诉操作员下一步。
  • 真实下单开关仍默认关闭,测试和调试参数不能打开。
  • 崩溃故障注入、全量 unittest、语法检查和离屏 UI 冒烟通过。

怎么验证

从 client/ 执行:

C:/Python310/python.exe -m py_compile src/purchase_task_service.py
$env:QT_QPA_PLATFORM="offscreen"
C:/Python310/python.exe -m unittest discover -s test -p "test_purchase*.py" -v
C:/Python310/python.exe -m unittest discover -s test -p "test_task_repository.py" -v
C:/Python310/python.exe -m unittest discover -s test -p "test_pdd_ui_event.py" -v
C:/Python310/python.exe -m unittest discover -s test -p "test_*.py"
Remove-Item Env:QT_QPA_PLATFORM

故障注入至少覆盖:领取后保存前、运行记录创建后、规格选择后、数量设置后、价格核对后、结果落库后、Outbox 发送前;另构造 irreversible_action_at 非空的历史运行,断言只核对且 purchase 调用次数为 0。

风险和回退

  • 这是采购安全关键代码。恢复规则不确定时必须转人工,不得猜测继续。
  • 不可逆标记非空后只核对订单是项目红线,任何方案变化都必须先停下来询问用户。
  • 真实下单安全门禁只能由项目负责人和实际操作人员共同验收;开发测试通过不等于放行。
  • 回退时保留任务、运行历史和 Outbox,不做破坏性清理。
## 基本信息 - 类型:需求 - 父级大工单:#1 - 所属 MVP / 版本:#2 Client 可运行任务闭环(MVP) - 阶段:5. 采购演练与恢复 - 依赖:#71、#72 - 状态:待实施 ## 要解决什么 采购演练可以执行和领取后,还必须验证崩溃、重复启动、结果提交失败和不可逆阶段恢复规则。虽然 MVP 不真实下单,但状态机和恢复路径必须先按真实安全边界建立,否则以后开启安全门禁时可能在进程崩溃后重复创建订单。 ## 做什么 / 不做什么 ### 做 - 完善采购 `task_runs` 步骤持久化和恢复判定,关键步骤进入前先提交 SQLite。 - 启动时检查未结束采购运行:未进入不可逆阶段的演练任务按明确规则恢复或失败;已存在 `irreversible_action_at` 的任务只进入订单核对/人工处理,绝不重新下单。 - 同一稳定任务 ID 和执行记录避免重复运行;Outbox 未发送时只补交结果,不重复执行采购。 - 实现 `reconcile_purchase` 的安全骨架:只读取、核对和记录结果,不点击下单或付款。 - 覆盖停止请求、设备断开、Client 重启、Admin 暂不可用、重复启动和结果不确定等场景。 - 界面用中文显示“演练完成、结果待提交、仅核对、需人工处理”等明确状态。 - 建立真实下单安全门禁自动化检查清单;本工单只验证,不放行 `live`。 - 更新质量、安全、数据模型和界面基线。 ### 不做 - 不打开真实下单开关,不点击提交订单,不付款。 - 不绕过验证码、登录或风控。 - 不自动清理已完成任务、执行历史和 Outbox。 - 不允许采购任务从“重新执行”入口启动。 - 不自行宣布真实下单安全门禁通过;最终放行必须由项目负责人和操作人员共同确认。 ## 已确认的实现方案 - 恢复决策只依赖 SQLite 已提交事实,不依赖内存标志或 Admin 当前状态。 - 所有可能通向不可逆动作的步骤先写 `current_step`;真实版本进入不可逆阶段前必须先写 `irreversible_action_at`。 - 恢复协调器按任务类型和运行事实分支:采集沿用原逻辑;采购一旦有不可逆标记,只调用只读核对接口。 - 演练模式不会写不可逆时间,但测试需要构造该历史状态,证明恢复代码绝不会调用 purchase。 - Outbox 与执行解耦:有未发送结果时先提交,不重新访问 PDD 页面。 - 使用可注入 Adapter/时钟/故障点覆盖“每一步后崩溃”的确定性测试。 预计修改:采购任务服务、恢复协调器、Repository 状态查询、只读核对 Adapter 接口、事件/UI 状态、质量安全测试和 Client 基线文档。 ## 验收标准 - [ ] 采购每个关键步骤进入前已经持久化,进程退出后能识别最后可靠步骤。 - [ ] 未进入不可逆阶段的演练运行按既定规则恢复,不产生第二条并发运行。 - [ ] `irreversible_action_at` 非空时只调用订单核对,任何路径都不会再次调用采购/下单。 - [ ] 结果已落 SQLite 但 Outbox 未发送时,只重试提交,不重新执行采购。 - [ ] 重复点击、自动获取重启和 Client 重启不会重复处理同一进行中采购任务。 - [ ] 停止、设备断开、验证码、登录失效和结果不确定会进入安全状态并保留诊断信息。 - [ ] 采购任务继续禁止“重新执行”。 - [ ] 界面状态和错误不只靠颜色,明确告诉操作员下一步。 - [ ] 真实下单开关仍默认关闭,测试和调试参数不能打开。 - [ ] 崩溃故障注入、全量 unittest、语法检查和离屏 UI 冒烟通过。 ## 怎么验证 从 `client/` 执行: ```powershell C:/Python310/python.exe -m py_compile src/purchase_task_service.py $env:QT_QPA_PLATFORM="offscreen" C:/Python310/python.exe -m unittest discover -s test -p "test_purchase*.py" -v C:/Python310/python.exe -m unittest discover -s test -p "test_task_repository.py" -v C:/Python310/python.exe -m unittest discover -s test -p "test_pdd_ui_event.py" -v C:/Python310/python.exe -m unittest discover -s test -p "test_*.py" Remove-Item Env:QT_QPA_PLATFORM ``` 故障注入至少覆盖:领取后保存前、运行记录创建后、规格选择后、数量设置后、价格核对后、结果落库后、Outbox 发送前;另构造 `irreversible_action_at` 非空的历史运行,断言只核对且 purchase 调用次数为 0。 ## 风险和回退 - 这是采购安全关键代码。恢复规则不确定时必须转人工,不得猜测继续。 - 不可逆标记非空后只核对订单是项目红线,任何方案变化都必须先停下来询问用户。 - 真实下单安全门禁只能由项目负责人和实际操作人员共同验收;开发测试通过不等于放行。 - 回退时保留任务、运行历史和 Outbox,不做破坏性清理。
Author
Owner

实施与验证已完成,准备提交。

  • 启动恢复只依赖 SQLite:无不可逆标记时先关闭旧运行,再以新 attempt 恢复演练;有不可逆标记时进入 manual_review / reconcile_purchase
  • 新增独立只读核对 Adapter/Service,接口没有选规格、下单或付款能力
  • 不可逆恢复测试断言:reconcile 调用 1 次,purchase 调用 0 次,重复轮询不会再次处理
  • 关键动作前持久化步骤,故障后运行记录保留最后可靠步骤与诊断
  • 采购设备错误转人工处理,不隐式自动重跑
  • purchase_mode=live 在能力对象创建时直接拒绝
  • 采购专项 12 项通过;Client 全量 207 项通过;语法检查和离屏主窗口冒烟通过
  • 未连接真实 Admin、Android 或 PDD;没有执行提交订单或付款。
实施与验证已完成,准备提交。 - 启动恢复只依赖 SQLite:无不可逆标记时先关闭旧运行,再以新 attempt 恢复演练;有不可逆标记时进入 `manual_review / reconcile_purchase` - 新增独立只读核对 Adapter/Service,接口没有选规格、下单或付款能力 - 不可逆恢复测试断言:reconcile 调用 1 次,purchase 调用 0 次,重复轮询不会再次处理 - 关键动作前持久化步骤,故障后运行记录保留最后可靠步骤与诊断 - 采购设备错误转人工处理,不隐式自动重跑 - `purchase_mode=live` 在能力对象创建时直接拒绝 - 采购专项 12 项通过;Client 全量 207 项通过;语法检查和离屏主窗口冒烟通过 - 未连接真实 Admin、Android 或 PDD;没有执行提交订单或付款。
Author
Owner

实现与归档已完成,等待用户验收。

  • 实现提交:c86c748 feat: 完善采购任务安全恢复 (#73)
  • 归档提交:c52d730 docs: 归档任务 #73
  • 归档文档:docs/task/73-采购任务安全恢复.md
  • 采购专项:12 项通过;Repository:14 项通过;Client 全量:207 项通过
  • 语法检查和 AGENTS.md 规定的离屏主窗口冒烟通过(输出 OK)
  • 安全断言:不可逆历史状态只调用 reconcile 1 次,purchase 0 次;purchase_mode=live 被拒绝
  • 未验证:真实 Admin、Android、PDD 和真实进程杀死;没有提交订单或付款;测试通过不代表真实下单门禁放行。
实现与归档已完成,等待用户验收。 - 实现提交:`c86c748 feat: 完善采购任务安全恢复 (#73)` - 归档提交:`c52d730 docs: 归档任务 #73` - 归档文档:`docs/task/73-采购任务安全恢复.md` - 采购专项:12 项通过;Repository:14 项通过;Client 全量:207 项通过 - 语法检查和 AGENTS.md 规定的离屏主窗口冒烟通过(输出 `OK`) - 安全断言:不可逆历史状态只调用 reconcile 1 次,purchase 0 次;`purchase_mode=live` 被拒绝 - 未验证:真实 Admin、Android、PDD 和真实进程杀死;没有提交订单或付款;测试通过不代表真实下单门禁放行。
Author
Owner

用户已于 2026-08-11 明确验收通过。

  • 本地归档状态已更新为“已完成,用户验收通过”
  • 验收记录提交:eca9289
  • 本工单按项目流程关闭
用户已于 2026-08-11 明确验收通过。 - 本地归档状态已更新为“已完成,用户验收通过” - 验收记录提交:`eca9289` - 本工单按项目流程关闭
ila closed this issue 2026-08-11 10:58:13 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chengma/cmautobuy#73