141 lines
8.3 KiB
Markdown
141 lines
8.3 KiB
Markdown
---
|
||
id: T-217
|
||
title: 已授权商品重新定位与订单 dry-run
|
||
phase: 2
|
||
deps:
|
||
- T-216
|
||
status: DONE
|
||
created: 2026-07-28
|
||
context_ref: 2372ab2
|
||
work_branch: null
|
||
write_paths:
|
||
- docs/tasks/T-217.md
|
||
- docs/00-ai-start-here.md
|
||
- docs/02-requirements.md
|
||
- docs/04-architecture.md
|
||
- docs/06-tasks.md
|
||
- docs/08-interaction-checklist.md
|
||
- docs/api.md
|
||
- docs/current-state.md
|
||
- docs/routes.md
|
||
- backend-api/migrations/**
|
||
- backend-api/internal/domain/**
|
||
- backend-api/internal/usecase/**
|
||
- backend-api/internal/repository/sqlite/**
|
||
- backend-api/internal/transport/httpapi/**
|
||
- android-buyer/app/src/main/**
|
||
- android-buyer/app/src/test/**
|
||
---
|
||
|
||
## 问题 / 背景
|
||
|
||
T-216 已把 Admin 选择的 candidate 作为不可变命令可靠保存到手机,但命令不包含可执行
|
||
第三方 URL,旧 ordinal 也不是商品身份。App 必须重新使用任务参考图进入拼多多图片
|
||
搜索,在变化的结果中重新核对 Admin 授权的 observation,确定性选择原 SKU 和数量,
|
||
并停在“确认订单”页的最终提交按钮之前。
|
||
|
||
本任务是 `ORDER_DRY_RUN`,不是订单提交。它允许进入规格弹层、确认规格并进入订单确认
|
||
页,但代码中不提供“提交订单/立即支付/确认支付”动作。只有 T-217 的本地与后端
|
||
READY 证据都存在,T-218 才能消费同一授权执行一次提交。
|
||
|
||
## 冻结合约
|
||
|
||
### 启动与恢复
|
||
|
||
1. 前台 execution service 只在本地 `PendingOrderCommand.acknowledged=true`、租约有效、
|
||
未取消且 readiness 仍满足时自动启动;不要求采购员再次点击,也不创建第二条命令。
|
||
2. App 先生成并加密保存 `PendingOrderDryRun`、start/ready 幂等键和 attempt 状态,再
|
||
调用 `POST /api/v1/tasks/{task_id}/order-dry-runs/start`。服务端只允许同一
|
||
user/device/task/execution/generation/command hash 的 `ACKNOWLEDGED` 授权进入
|
||
`EXECUTING`;响应丢失可安全重放。
|
||
3. 进程在 READY 前退出时,不假定拼多多仍停在可信页面。恢复后先识别并安全返回,
|
||
再从参考图重新执行有界定位;不从上次坐标或旧 ordinal 继续。
|
||
4. T-216 command pull 对同一 `EXECUTING` 授权继续返回相同 command/hash,支持本地
|
||
加密状态丢失后的安全恢复,但不得因此创建第二次授权。
|
||
|
||
### 重新图片搜索与候选唯一定位
|
||
|
||
1. 每次尝试重新校验本地参考 JPEG 的 SHA-256,使用 T-211 的一次性 MediaStore 图片
|
||
重新进入拼多多图片结果;最多检查 10 个卡片、滚动 2 次,预算在动作前扣减且重试
|
||
不重置。
|
||
2. `observed_ordinal` 只用于审计,不能作为点击索引。每个实际检查项重新采集 card
|
||
signature、detail signature、可见标题、规格证据、当前组合价格和新截图哈希。
|
||
3. 候选必须至少有一个旧的语义签名(card/detail)精确命中,同时标题规范化一致;
|
||
之后颜色与尺码必须按原始 SKU 各自唯一匹配并复核 selected/“已选择”摘要。旧详情/
|
||
规格截图 hash 只证明 Admin 当时的依据,不要求新截图逐像素相同。
|
||
4. 当前组合价格必须能严格解析为单一人民币分值。有任务总预算时,
|
||
`unit_price * quantity <= max_budget`;没有预算时当前单价必须等于授权候选的严格
|
||
可解析单价。区间、券后、条件、多价格冲突或价格上涨均停止。
|
||
5. 只有一个候选通过全部条件才能继续。零个或多个命中、签名全部变化、标题冲突、
|
||
SKU 不唯一、库存/控件禁用或价格不满足时安全停止。VLM 可辅助排序和解释截图,
|
||
但不能替代任一确定性条件或发出点击。
|
||
|
||
### SKU、数量与订单确认页
|
||
|
||
1. 从已唯一定位的详情页只允许用 T-213 已验证的规格入口进入弹层。颜色、尺码按目标
|
||
唯一选择;数量控件必须有可访问的当前数值与唯一加减语义,目标数量 `1..99`,点击
|
||
次数有界且每次后读验证。不能用坐标或长按填数量。
|
||
2. 规格、数量和价格全部复核后,允许点击规格弹层内唯一的“确定”语义控件进入
|
||
`ORDER_CONFIRMATION`。该动作只是形成待提交订单预览,不是平台订单提交。
|
||
3. 订单确认页重新读取商品标题/规格摘要/数量/商品金额或应付总额;必须与授权和弹层
|
||
证据一致,且总额不超过任务最高商品总预算。地址、优惠券、运费或服务选项只读,
|
||
App 不自动修改。拼多多 WebView 无法暴露完整语义树时,只允许对当前无障碍截图
|
||
使用端上中文 OCR 做只读、fail-closed 核验;标题锚点、SKU 别名、数量和实付款任一
|
||
缺失或冲突都停止,OCR 结果不能产生点击。
|
||
4. 捕获受控订单确认截图后,App 先加密保存 READY 证据,再上传截图并幂等调用
|
||
`POST /api/v1/tasks/{task_id}/order-dry-runs/{command_id}/ready`。服务端保存当前
|
||
指纹、SKU、数量、价格、金额和 evidence,写 `ORDER_DRY_RUN_READY` 事件。
|
||
5. 服务端确认后 UI 显示“订单已核验,等待单次提交”。App 保持前台服务和租约,
|
||
不点击确认订单页的提交控件;重启复用同一 READY 记录。
|
||
|
||
## 数据模型
|
||
|
||
v10:
|
||
|
||
- `order_dry_runs`:每个 authorization 唯一一行,保存 PREPARING/READY、命令 hash、
|
||
本次 card/detail 指纹、标题、SKU、数量、单价/总额、受控 evidence 和时间;
|
||
- `device_order_dry_run_requests`:按 device + operation + idempotency key 保存请求
|
||
hash 与结果引用;
|
||
- task events 增加 `ORDER_DRY_RUN_STARTED` 和 `ORDER_DRY_RUN_READY`。
|
||
|
||
存在 dry-run 数据或新事件时 destructive down 必须失败。授权沿用 v8 已有
|
||
`ACKNOWLEDGED -> EXECUTING`,T-217 不增加订单已提交或付款状态。
|
||
|
||
## 验收要点
|
||
|
||
- [x] start/ready 仅接受原身份、有效租约、同一 command hash,并可安全重放。
|
||
- [x] 重新定位不按 ordinal/坐标;预算、滚动和候选检查均有硬上限。
|
||
- [x] 至少一个旧语义签名、标题、唯一 SKU 和价格/预算同时满足,且只能唯一命中。
|
||
- [x] 数量设置逐步复核;禁用、重复、缺失和状态未改变均停止。
|
||
- [x] 只允许从规格弹层进入订单确认页,绝不点击订单提交或支付控件。
|
||
- [x] READY 先加密落盘再回传,截图/当前指纹/SKU/数量/金额可审计并可恢复。
|
||
- [x] v10 migration、Go test/race/vet、Android test/Debug/Release 和根验证通过。
|
||
- [x] PKG110 真机 smoke 到订单确认页,后端 READY 且未触发最终提交。
|
||
|
||
## 边界
|
||
|
||
- 不点击确认订单页最终提交,不创建平台订单;属于 T-218。
|
||
- 不读取订单列表、订单号或下单时间;属于 T-218。
|
||
- 不提示或执行付款;属于 T-219/采购员人工操作。
|
||
- 不用 VLM、坐标、剪贴板或旧截图 hash 绕过确定性核验;OCR 仅用于当前结算截图
|
||
的只读证据降级,不能放宽 SKU/数量/金额条件或产生点击。
|
||
|
||
## 执行记录
|
||
|
||
- 2026-07-28:T-216 实现提交 `2372ab2` 后领取。冻结自动触发、恢复、重新图片搜索、
|
||
多信号唯一定位、SKU/数量/价格复核和最终提交禁区;计划复用 T-211/T-213 已验证的
|
||
图片搜索、规格解析和页面分类能力。
|
||
- 2026-07-28:新增 v10 dry-run/幂等请求表、start/ready API、授权
|
||
`ACKNOWLEDGED -> EXECUTING`、加密本地 PREPARING/READY 与证据 outbox。Android
|
||
`1.4.14 (19)` 增加重新定位、规格/数量设置、确认页只读核验和最多 5 次恢复尝试。
|
||
- 2026-07-28:真机发现拼多多拍照搜索偶发“请对准商品或码”对话框,状态机只允许
|
||
点击“取消”后重新进入相册;结算 WebView 语义树折叠时使用 bundled ML Kit 中文
|
||
OCR,按规范色别名、尺码、数量和实付款 fail-closed 核验。
|
||
- 2026-07-28:PKG110/拼多多 8.17 真机任务
|
||
`670019e0-20d9-453e-a67e-964e03ad7482` 到达后端 READY;保存订单确认截图、
|
||
`灰色,2XL`、数量 1、单价/总额 14.35 元以及 STARTED/READY 事件。App 显示
|
||
“订单已核验,等待提交”,没有调用订单提交或支付动作。
|
||
- 2026-07-28:`go test ./...`、`go test -race ./...`、`go vet ./...`、Android
|
||
Debug/Release 单测与构建、根 `.\init.ps1` 全部通过;正式 APK 已覆盖安装并保留
|
||
READY 状态。
|