diff --git a/docs/task/257-client安全应用运行时规格解析.md b/docs/task/257-client安全应用运行时规格解析.md new file mode 100644 index 0000000..3e7da15 --- /dev/null +++ b/docs/task/257-client安全应用运行时规格解析.md @@ -0,0 +1,65 @@ +# 257 Client:安全应用 Admin 规格解析结果并继续采购 + +- 类型:需求 +- 父级大工单:#96(关联 Client Epic #1) +- 所属 MVP / 版本:#253 采购运行时 AI 规格纠偏闭环 +- 状态:已完成 +- 日期:2026-08-17 +- Gitea 工单: + +## 背景与目标 + +#256 已能在目标尺码无法精确匹配时,生成当前商品、颜色和完整可购买尺码候选快照。本任务把该快照先保存到本地,再通过专用 Admin 命令请求一次规格解析;只有返回本次候选中的唯一匹配项,并且真机页面复查未变化时,才继续原有采购安全流程。 + +## 最终方案 + +- 为 Admin Gateway、HTTP Gateway 和 Mock Gateway 增加一次性 `resolve_purchase_spec` 命令,统一解析结果和错误语义。 +- SQLite 升级到 schema v6,新增 `purchase_spec_resolutions` 表。请求在网络发送前落库,使用任务、执行尝试和候选哈希生成确定性幂等键;响应也先保存,再允许操作手机。 +- `PurchaseTaskService` 捕获 #256 的结构化候选观察,单次调用 Admin。`uncertain`、`rejected`、`failed`、网络错误和非法响应均安全结束,不循环请求,也不自动重新采购。 +- Admin 返回 `matched` 后,U2 Adapter 重新读取商品页、已选颜色和全部尺码候选,复算快照哈希,只按返回候选的页面原文精确点击并确认选中。 +- 数量、订单总价上限、地址、不可逆标记、单次下单和只读核单继续走原有门禁。原任务规格不被覆盖;成功结果和失败诊断记录解析编号与实际采用规格。 +- 实现与建单方案一致。真实 Admin 与真机端到端验证按 #258 单独执行。 + +## 改了哪些 + +- `client/src/admin_gateway.py`、`http_admin_gateway.py`、`mock_admin_gateway.py`:增加规格解析 DTO、HTTP 命令、严格响应校验和 Mock 幂等行为。 +- `client/src/db_schema.py`、`task_models.py`、`task_repository.py`:增加 schema v6、解析记录模型以及请求先落库、响应审计和冲突保护。 +- `client/src/purchase_task_service.py`:接入一次性解析流程,保持原规格和有效规格分离,并复用原采购安全门禁。 +- `client/src/pdd_purchase_adapter.py`、`pdd_u2_purchase_adapter.py`:增加解析结果应用边界,重新读取并核对真机候选后精确选择。 +- `client/src/pdd_purchase_reconcile_adapter.py`、`purchase_reconcile_service.py`:核单结果保留原请求规格、实际规格和解析审计信息。 +- `client/test/` 相邻测试:覆盖 Gateway 契约、HTTP 响应、Mock 幂等、SQLite 迁移、Repository、采购服务、页面变化和核单结果。 +- `docs/client/03-data-model.md`、`docs/client/06-quality-security.md`:补充本地表结构、持久化边界和采购安全规则。 + +## 验收结果 + +| 验收标准 | 结果 | +|---|---| +| 请求发送前持久化,相同任务、尝试和候选哈希复用同一内容与幂等键 | 通过 | +| HTTP 与 Mock 支持 matched、uncertain、rejected、failed、超时和幂等语义 | 通过 | +| 网络、SQLite 和 uiautomator2 仍由既有后台任务链调用,不新增 Qt 主线程阻塞 | 通过 | +| 只有响应哈希、候选编号、原文和 options 全部匹配时才继续 | 通过 | +| 继续前重新核对商品、颜色和候选快照,变化或无法确认选中时停止 | 通过 | +| 继续复用数量、总价、地址、不可逆标记、单次提交和只读核单门禁 | 通过 | +| 网络或业务解析失败不循环请求、不自动重新采购,并形成可追溯失败 | 通过 | +| 不可逆运行保持只读核单路径,不因规格解析重新调用采购 Adapter | 通过 | +| 最终结果包含解析编号和实际规格,不保存凭据、原始 XML 或个人数据 | 通过 | +| Python 3.10 定向测试、迁移测试、编译和离屏 UI 冒烟 | 通过 | + +## 测试 + +- 执行的命令: + - `C:/Python310/python.exe -m pytest test/test_admin_gateway_contract.py test/test_http_admin_gateway.py test/test_db.py test/test_task_repository.py test/test_purchase_task_service.py test/test_pdd_u2_purchase_adapter.py test/test_pdd_u2_purchase_reconcile_adapter.py -q` + - `C:/Python310/python.exe -m pytest test -q` + - `C:/Python310/python.exe -m py_compile src/admin_gateway.py src/db_schema.py src/http_admin_gateway.py src/mock_admin_gateway.py src/pdd_purchase_adapter.py src/pdd_purchase_reconcile_adapter.py src/pdd_u2_purchase_adapter.py src/purchase_reconcile_service.py src/purchase_task_service.py src/task_models.py src/task_repository.py` + - 设置 `QT_QPA_PLATFORM=offscreen` 后创建并关闭 `MainWindow`。 +- 结果:定向测试 162 项全部通过;编译和离屏 UI 冒烟通过。Client 全量测试 492 项通过、2 项失败,失败均为工作区现有 `0.1.2` 版本号与旧测试固定期望 `0.1.0` 不一致,与 #257 无关。直接从 `client/` 执行无路径限制的 `pytest -q` 还会因 `test/` 和 `tools/` 中同名测试脚本产生既有收集冲突,因此全量单元测试明确使用 `pytest test -q`。 +- **没验证到的部分**:未连接真实 Admin 和 Android 真机执行完整解析后下单链路;该验证属于 #258。没有进行自动付款。 + +## 遗留问题 + +- 真实 Admin、不同 PDD 页面结构和网络中断时的端到端表现由 #258 验证。 +- 版本号相关的 2 个既有测试失败和同名脚本收集冲突不在本工单范围内。 + +## 相关提交 + +- `afc1cdf` 安全应用采购规格解析结果并继续采购。