Files
cmautobuy/docs/task/257-client安全应用运行时规格解析.md
T

78 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 257 Client:安全应用 Admin 规格解析结果并继续采购
- 类型:需求
- 父级大工单:#96(关联 Client Epic #1)
- 所属 MVP / 版本:#253 采购运行时 AI 规格纠偏闭环
- 状态:已完成
- 日期:2026-08-17
- Gitea 工单:<http://ilaer.eicp.net:8418/chengma/cmautobuy/issues/257>
## 背景与目标
#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 重新读取商品页、已选颜色和全部尺码候选,复算快照哈希,只按返回候选的页面原文精确点击并确认选中。
- 数量、订单总价上限、地址、不可逆标记、单次下单和只读核单继续走原有门禁。原任务规格不被覆盖;成功结果和失败诊断记录解析编号与实际采用规格。
- 2026-08-18 本地联调确认,Client 原本复用了普通 Admin 请求的 3 秒短超时,导致 Admin 的 AI 调用尚未完成时 Client 已断开,HTTP 请求上下文随之取消并返回 `PURCHASE_SPEC_RESOLUTION_ADMIN_FAILED`。现改为只有规格解析命令最多等待 60 秒;Admin 的本次运行时 AI 调用最多等待 30 秒,服务商配置更短时仍以更短值为准,并继承 Client 的更早取消。
- #258 联合验收发现 Mock 的请求校验比真实 Admin 宽松;补充修正后,Mock 同样校验请求体 64 KiB、字段长度和控制字符、带时区观测时间、领取任务中的颜色/尺码,以及任务不存在和从未领取的稳定错误代码。
- 实现与建单方案一致。真实 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、采购服务、页面变化和核单结果。
- `client/test/test_admin_gateway_contract.py`:补充 Admin/Mock 请求边界和任务身份错误码一致性回归。
- `client/src/http_admin_gateway.py`、`client/test/test_http_admin_gateway.py`、`client/test/test_purchase_spec_resolution_contract_vectors.py`:为规格解析命令设置 60 秒独立等待上限,并验证普通 Admin 请求继续使用原短超时。
- `admin/service/purchase_spec_resolution.go`、`admin/service/purchase_spec_resolution_test.go`:为采购运行时 AI 设置 30 秒上下文上限,并验证继承请求的更早取消。
- `docs/client/04-admin-api-contract.md`、`docs/admin/04-client-api.md`:同步跨端时间预算契约。
- `docs/client/03-data-model.md`、`docs/client/06-quality-security.md`:补充本地表结构、持久化边界和采购安全规则。
## 验收结果
| 验收标准 | 结果 |
|---|---|
| 请求发送前持久化,相同任务、尝试和候选哈希复用同一内容与幂等键 | 通过 |
| HTTP 与 Mock 支持 matched、uncertain、rejected、failed、超时和幂等语义 | 通过 |
| 网络、SQLite 和 uiautomator2 仍由既有后台任务链调用,不新增 Qt 主线程阻塞 | 通过 |
| 只有响应哈希、候选编号、原文和 options 全部匹配时才继续 | 通过 |
| 继续前重新核对商品、颜色和候选快照,变化或无法确认选中时停止 | 通过 |
| 继续复用数量、总价、地址、不可逆标记、单次提交和只读核单门禁 | 通过 |
| 网络或业务解析失败不循环请求、不自动重新采购,并形成可追溯失败 | 通过 |
| 不可逆运行保持只读核单路径,不因规格解析重新调用采购 Adapter | 通过 |
| 最终结果包含解析编号和实际规格,不保存凭据、原始 XML 或个人数据 | 通过 |
| Client 仅为规格解析等待最多 60 秒,普通 Admin 请求仍使用原短超时 | 通过 |
| Admin 运行时 AI 最多等待 30 秒,并继承更早取消 | 通过 |
| 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`。
- #258 补充验证:`C:/Python310/python.exe -m pytest -q test/test_admin_gateway_contract.py test/test_http_admin_gateway.py test/test_purchase_task_service.py test/test_pdd_u2_purchase_adapter.py test/test_task_repository.py test/test_purchase_recovery.py`,148 项通过;`py_compile` 和 `git diff --check` 通过。
- 2026-08-18 超时修复验证:Admin 使用 Go 1.23.0 执行 `gofmt -l .`、`go test ./... -count=1`、`go build ./...`、`go vet ./...`,全部通过;Client 超时及共享契约定向测试 19 项通过;Client 全量测试 500 项通过、2 项既有版本号断言失败,排除对应两个测试文件后 480 项通过;离屏创建并关闭 `MainWindow` 通过。
- **没验证到的部分**:未连接真实 Admin 和 Android 真机执行完整解析后下单链路;该验证属于 #258。没有进行自动付款。
## 遗留问题
- 真实 Admin、不同 PDD 页面结构和网络中断时的端到端表现由 #258 验证。
- 版本号相关的 2 个既有测试失败和同名脚本收集冲突不在本工单范围内。
## 相关提交
- `afc1cdf` 安全应用采购规格解析结果并继续采购。
- `1009e54` 对齐规格解析 Mock 请求校验和稳定错误代码。
- `6345b00` 对齐 Client 60 秒与 Admin AI 30 秒跨端超时预算。