docs(t218): freeze single-submit reconciliation contract
This commit is contained in:
@@ -3,7 +3,8 @@
|
|||||||
## 一句话定位
|
## 一句话定位
|
||||||
|
|
||||||
本项目验证管理后台创建的图片和文字采购任务,能否由 Android App 领取并借助 VLM
|
本项目验证管理后台创建的图片和文字采购任务,能否由 Android App 领取并借助 VLM
|
||||||
在拼多多中找到合理候选商品,同时安全地停在人工确认位置并回传证据。
|
在拼多多中找到合理候选商品;Admin 选品后 App 只创建一笔待付款订单、回传订单号,
|
||||||
|
再由采购人员在拼多多人工确认付款。
|
||||||
|
|
||||||
## 当前 MVP
|
## 当前 MVP
|
||||||
|
|
||||||
@@ -13,13 +14,14 @@
|
|||||||
- 一台 Android 设备由采购人员手动领取下一条任务。
|
- 一台 Android 设备由采购人员手动领取下一条任务。
|
||||||
- AI 把图片和文字解析为结构化检索条件。
|
- AI 把图片和文字解析为结构化检索条件。
|
||||||
- App 在拼多多搜索、检查少量结果并选择候选。
|
- App 在拼多多搜索、检查少量结果并选择候选。
|
||||||
- App 停在候选确认或订单确认页,由人判断是否通过。
|
- Admin 确认候选后,App 复核 SKU/数量/金额并最多创建一笔待付款订单。
|
||||||
- 回传任务状态、候选摘要、截图和失败原因。
|
- 回传任务状态、候选摘要、截图和失败原因。
|
||||||
|
- 唯一对账订单号与下单时间,提醒采购人员去拼多多人工付款。
|
||||||
|
|
||||||
不做:
|
不做:
|
||||||
|
|
||||||
- 推送到达后无人确认地立即执行。
|
- 推送到达后无人确认地立即执行。
|
||||||
- 最终提交订单、自动付款或处理退款。
|
- 自动付款、免密支付、自动修改地址或处理退款。
|
||||||
- 绕过验证码、风控或登录校验。
|
- 绕过验证码、风控或登录校验。
|
||||||
- 多电商平台、多设备并发调度和生产级 RBAC。
|
- 多电商平台、多设备并发调度和生产级 RBAC。
|
||||||
|
|
||||||
@@ -59,7 +61,7 @@ T-205 原子领取/租约状态机、T-206 Android 登录/有限离线、T-207
|
|||||||
规格组合/价格核验均已完成。T-208 的原始候选观测、模型评估、确定性推荐、逐候选
|
规格组合/价格核验均已完成。T-208 的原始候选观测、模型评估、确定性推荐、逐候选
|
||||||
结构化人工理由和修订历史也已完成。T-214 商品持久身份和重新定位指纹、T-215
|
结构化人工理由和修订历史也已完成。T-214 商品持久身份和重新定位指纹、T-215
|
||||||
Admin 候选确认、不可变待投递授权、T-216 设备命令可靠投递及 T-217 已授权商品
|
Admin 候选确认、不可变待投递授权、T-216 设备命令可靠投递及 T-217 已授权商品
|
||||||
重新定位与订单 dry-run 均已完成;下一项是 T-218 单次订单提交与订单回读。
|
重新定位与订单 dry-run 均已完成;T-218 单次订单提交与订单回读正在开发。
|
||||||
不得直接把候选链接或列表 ordinal 当成授权。
|
不得直接把候选链接或列表 ordinal 当成授权。
|
||||||
手机从管理后端领取任务并回传结果,VLM、拼多多自动化和人工确认在 App 本地完成。
|
手机从管理后端领取任务并回传结果,VLM、拼多多自动化和人工确认在 App 本地完成。
|
||||||
T-206 增加有限离线执行;T-207 已复用 Roubao 端上 OpenAI 兼容适配器并加密本地 Key。
|
T-206 增加有限离线执行;T-207 已复用 Roubao 端上 OpenAI 兼容适配器并加密本地 Key。
|
||||||
|
|||||||
@@ -132,6 +132,10 @@ T-206/T-207 已跑通领取、执行、候选/证据和最小结果回传;T-20
|
|||||||
review version、原始 SKU 和数量;URL、列表 ordinal 或模型推荐均不能单独授权。
|
review version、原始 SKU 和数量;URL、列表 ordinal 或模型推荐均不能单独授权。
|
||||||
22. 一个授权最多创建一个拼多多订单。网络超时或页面不确定时必须先对账,不能重按
|
22. 一个授权最多创建一个拼多多订单。网络超时或页面不确定时必须先对账,不能重按
|
||||||
提交;系统不保存支付凭证,不点击付款。
|
提交;系统不保存支付凭证,不点击付款。
|
||||||
|
23. 创建提交围栏前必须重新确认地址已配置且订单字段仍与 dry-run 一致;最终按钮必须
|
||||||
|
唯一且文本精确为“提交订单”。出现添加地址、立即支付、免密支付、先用后付或其他
|
||||||
|
自动扣款语义时必须停止。围栏创建后即使 App 在实际点击前退出,也只能查订单或
|
||||||
|
转人工,不能重新提交。
|
||||||
|
|
||||||
## 六、第一层本地样本约定
|
## 六、第一层本地样本约定
|
||||||
|
|
||||||
|
|||||||
+29
-1
@@ -634,6 +634,32 @@ App 可以从规格弹层进入确认订单页,但 T-217 的 accessibility act
|
|||||||
颜色/尺码必须通过同一 SKU 别名匹配器、数量必须位于规格与优惠边界之间,实付款必须
|
颜色/尺码必须通过同一 SKU 别名匹配器、数量必须位于规格与优惠边界之间,实付款必须
|
||||||
唯一可解析。任一条件不满足即停止,OCR 层没有点击接口。
|
唯一可解析。任一条件不满足即停止,OCR 层没有点击接口。
|
||||||
|
|
||||||
|
### 单次订单提交与回读(T-218)
|
||||||
|
|
||||||
|
```text
|
||||||
|
local READY + backend READY + valid lease
|
||||||
|
-> revalidate confirmation/address/manual-payment boundary
|
||||||
|
-> idempotent backend submission fence (authorization becomes non-repeatable)
|
||||||
|
-> persist encrypted CLICK_ASSUMED
|
||||||
|
-> at most one exact "提交订单" accessibility action
|
||||||
|
-> never click payment; navigate read-only to order list
|
||||||
|
-> unique pending-order reconciliation
|
||||||
|
-> RECONCILED or MANUAL_REVIEW, never a second submit
|
||||||
|
```
|
||||||
|
|
||||||
|
submission fence 是 exactly-once 安全边界,不是“点击成功”回执。服务端创建围栏后,
|
||||||
|
任何进程恢复都假定订单可能已创建;宁可留下需要人工对账的未提交意图,也不能通过
|
||||||
|
重按产生重复订单。一个 authorization 和 dry-run 在数据库中只能对应一个 submission。
|
||||||
|
|
||||||
|
不可逆动作前再次核对 T-217 全部商品字段,并要求明确可见的已配置地址和唯一
|
||||||
|
“提交订单”节点。地址缺失、金额变化、自动扣款方式或“立即支付/确认支付/免密支付/
|
||||||
|
先用后付”语义均阻塞。OCR 和 VLM 只能提供只读证据,不能决定或发出提交。
|
||||||
|
|
||||||
|
点击后只读检查有限数量的最近/待付款订单。归属必须由订单编号标签、平台下单时间、
|
||||||
|
待付款状态、标题、SKU、数量和金额共同唯一确定;零个或多个匹配转人工。订单号和时间
|
||||||
|
只进入 App 加密状态与鉴权后端,不进入普通日志或模型请求。T-219 读取该对账记录展示
|
||||||
|
待付款提醒,所有支付仍由采购人员在拼多多完成。
|
||||||
|
|
||||||
人工理由使用版本化 allowlist。接受或拒绝至少有一个理由且指定主要理由;
|
人工理由使用版本化 allowlist。接受或拒绝至少有一个理由且指定主要理由;
|
||||||
`OTHER` 才要求 4-200 字备注。拒绝推荐后改选必须同时产生一条原推荐项负标签和一条
|
`OTHER` 才要求 4-200 字备注。拒绝推荐后改选必须同时产生一条原推荐项负标签和一条
|
||||||
替代项正标签;全部无匹配时每个曝光候选都有负标签。人工修正追加新 review 并引用
|
替代项正标签;全部无匹配时每个曝光候选都有负标签。人工修正追加新 review 并引用
|
||||||
@@ -669,7 +695,9 @@ App 可以从规格弹层进入确认订单页,但 T-217 的 accessibility act
|
|||||||
- 截图发送给模型前裁剪无关区域并按配置脱敏。
|
- 截图发送给模型前裁剪无关区域并按配置脱敏。
|
||||||
- 每个动作记录抽象步骤,不默认记录完整输入文本。
|
- 每个动作记录抽象步骤,不默认记录完整输入文本。
|
||||||
- 发现验证码、风险控制、支付、生物识别或系统权限页面立即停止。
|
- 发现验证码、风险控制、支付、生物识别或系统权限页面立即停止。
|
||||||
- MVP 用代码级 allowlist 禁止所有已知“提交订单/支付”动作;不能仅靠提示词约束模型。
|
- T-217 及更早流程用代码级 allowlist 禁止“提交订单/支付”;T-218 只在服务端围栏和
|
||||||
|
`CLICK_ASSUMED` 持久化后开放一次精确“提交订单”,支付动作始终禁止,不能仅靠
|
||||||
|
提示词约束模型。
|
||||||
|
|
||||||
## 八、错误分类
|
## 八、错误分类
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| T-301 | 完成 P0 UI 实现和交互验收 | T-203、T-206 | Web 和 App 的 IX 默认/加载/错误/中断状态均有验证证据 |
|
| T-301 | 完成 P0 UI 实现和交互验收 | T-203、T-206 | Web 和 App 的 IX 默认/加载/错误/中断状态均有验证证据 |
|
||||||
| T-302 | 建立脱敏、清理和审计策略 | T-207 | 日志/截图不泄密;文件保留和清理可配置;事件可追溯 |
|
| T-302 | 建立脱敏、清理和审计策略 | T-207 | 日志/截图不泄密;文件保留和清理可配置;事件可追溯 |
|
||||||
| T-303 | 运行 20 条真实采购任务试验 | T-301、T-302、T-208 | 指标按人工标签统计;曝光候选和理由完整;失败分类完整;无订单提交 |
|
| T-303 | 运行 20 条真实采购任务试验 | T-301、T-302、T-208 | 指标按人工标签统计;曝光候选和理由完整;失败分类完整;订单提交严格受围栏控制且无自动付款 |
|
||||||
| T-304 | 可行性评审和 V2 决策 | T-303 | 对照 80%/70% 门槛给出继续、修正或停止结论 |
|
| T-304 | 可行性评审和 V2 决策 | T-303 | 对照 80%/70% 门槛给出继续、修正或停止结论 |
|
||||||
|
|
||||||
## Phase 4:交付验证版
|
## Phase 4:交付验证版
|
||||||
|
|||||||
@@ -333,6 +333,7 @@
|
|||||||
- 投递后不能静默改选;必须先走设备停止/撤销协议。
|
- 投递后不能静默改选;必须先走设备停止/撤销协议。
|
||||||
- 商品无法重新定位、SKU/数量/价格不一致、地址/运费/优惠导致金额不确定时停止,
|
- 商品无法重新定位、SKU/数量/价格不一致、地址/运费/优惠导致金额不确定时停止,
|
||||||
不提交订单。
|
不提交订单。
|
||||||
|
- 页面要求添加地址、最终按钮不是唯一的“提交订单”或出现免密/自动扣款语义时停止。
|
||||||
- 提交响应超时或页面未知时显示“正在对账”,禁止再次提交;没有唯一新订单时转人工。
|
- 提交响应超时或页面未知时显示“正在对账”,禁止再次提交;没有唯一新订单时转人工。
|
||||||
- 页面和 App 都不能提供自动付款按钮。
|
- 页面和 App 都不能提供自动付款按钮。
|
||||||
|
|
||||||
|
|||||||
+29
@@ -314,6 +314,35 @@ App 到达确认订单页并先加密保存 READY 后,提交当前 card/detail
|
|||||||
task/execution/claim、数量、预算和 evidence 归属后,把同一 dry-run 置为 READY 并写
|
task/execution/claim、数量、预算和 evidence 归属后,把同一 dry-run 置为 READY 并写
|
||||||
事件;相同请求可重放。该响应不表示订单已提交,且不授权付款。
|
事件;相同请求可重放。该响应不表示订单已提交,且不授权付款。
|
||||||
|
|
||||||
|
### `POST /api/v1/tasks/{task_id}/order-submissions/start`
|
||||||
|
|
||||||
|
T-218 App 在最终提交前调用。请求带 BUYER bearer、claim token、
|
||||||
|
`Idempotency-Key`,body 固定 device、execution、generation、authorization、
|
||||||
|
command id/hash、dry-run id/hash 和 App 重新核验的 SKU/数量/单价/总额。服务端要求
|
||||||
|
有效租约、未取消、authorization=`EXECUTING`、dry-run=`READY` 且所有快照完全一致。
|
||||||
|
|
||||||
|
成功事务内创建一个 `order_submission`、写 `ORDER_SUBMISSION_FENCED` 并使原授权
|
||||||
|
不可再次创建 submission。响应返回稳定 submission ID 和 `fenced_at`。同 key/body
|
||||||
|
重放返回相同记录;同 key 不同 body、第二个 submission 或非 READY 返回冲突。围栏
|
||||||
|
成功只表示 App 获得过一次点击机会;从此即使响应丢失或 App 退出也只能对账,不能
|
||||||
|
再次提交。
|
||||||
|
|
||||||
|
### `POST /api/v1/tasks/{task_id}/order-submissions/{submission_id}/reconcile`
|
||||||
|
|
||||||
|
App 唯一识别待付款订单并先上传受控 evidence 后,提交订单编号、平台显示下单时间、
|
||||||
|
标题、SKU、数量、金额、状态和 evidence asset/hash。服务端核对原 device/task/
|
||||||
|
execution/generation、submission、期望快照、证据归属和幂等键;成功将 submission
|
||||||
|
置为 `RECONCILED`、authorization 置为 `CONSUMED` 并记录
|
||||||
|
`order_submitted=true`。订单编号不得进入 URL、日志、事件 message 或模型字段。
|
||||||
|
|
||||||
|
### `POST /api/v1/tasks/{task_id}/order-submissions/{submission_id}/manual-review`
|
||||||
|
|
||||||
|
围栏后无法唯一回读订单时,App 用相同身份提交受限 reason code 和可选 evidence。
|
||||||
|
服务端将 submission 置为 `MANUAL_REVIEW` 并写审计事件,但不释放围栏、不允许生成
|
||||||
|
第二个 submission。后续只允许人员或同一设备重新对账,不提供“重试提交”接口。
|
||||||
|
|
||||||
|
三个接口都不接收支付方式、支付密码或付款结果,也不授权客户端点击付款控件。
|
||||||
|
|
||||||
## 设备与领取
|
## 设备与领取
|
||||||
|
|
||||||
### `POST /api/v1/devices/heartbeat`
|
### `POST /api/v1/devices/heartbeat`
|
||||||
|
|||||||
+10
-4
@@ -5,7 +5,7 @@
|
|||||||
## 当前快照
|
## 当前快照
|
||||||
|
|
||||||
- 日期:2026-07-28
|
- 日期:2026-07-28
|
||||||
- 阶段:T-217 已授权商品重新定位与订单 dry-run 已完成;下一项 T-218
|
- 阶段:T-218 单次订单提交与订单回读已领取,合约冻结中
|
||||||
- Git:当前分支为 `main`;T-001 至 T-004、T-101 至 T-104、T-201 至 T-217
|
- Git:当前分支为 `main`;T-001 至 T-004、T-101 至 T-104、T-201 至 T-217
|
||||||
均按文档提交、实现提交的顺序纳入历史
|
均按文档提交、实现提交的顺序纳入历史
|
||||||
- 生产代码:`android-buyer/` 已接入 Roubao Android 源码
|
- 生产代码:`android-buyer/` 已接入 Roubao Android 源码
|
||||||
@@ -76,6 +76,9 @@
|
|||||||
唯一颜色/尺码、数量和预算重新核验 Admin 选择;确认页 WebView 折叠时使用端上
|
唯一颜色/尺码、数量和预算重新核验 Admin 选择;确认页 WebView 折叠时使用端上
|
||||||
中文 OCR 做只读 fail-closed 证据提取。后端保存 v10 READY、截图、SKU、数量、
|
中文 OCR 做只读 fail-closed 证据提取。后端保存 v10 READY、截图、SKU、数量、
|
||||||
单价/总额和事件;无障碍动作集中不含订单提交或支付。
|
单价/总额和事件;无障碍动作集中不含订单提交或支付。
|
||||||
|
- T-218 目标:后端先创建一次性 submission fence,App 点击前持久化
|
||||||
|
`CLICK_ASSUMED`,最多点击一次精确“提交订单”;进程/网络不确定后只回读待付款
|
||||||
|
订单或转人工,绝不重复提交或点击支付。
|
||||||
- Workflow:纯 Kotlin runner 已支持步骤 timeout、最多 3 次 retry、安全阻塞、
|
- Workflow:纯 Kotlin runner 已支持步骤 timeout、最多 3 次 retry、安全阻塞、
|
||||||
用户停止和单 runner 并发拒绝;T-102 已接入搜索加有界候选采集五步
|
用户停止和单 runner 并发拒绝;T-102 已接入搜索加有界候选采集五步
|
||||||
- TaskSource:严格 CLI 已生成并验证真实私有 ProbeTask;默认 APK 不含私有 fixture
|
- TaskSource:严格 CLI 已生成并验证真实私有 ProbeTask;默认 APK 不含私有 fixture
|
||||||
@@ -104,8 +107,10 @@
|
|||||||
已用 CLI 真实导入并逐字段/图片哈希验证,生成物位于被忽略的 `.local/`
|
已用 CLI 真实导入并逐字段/图片哈希验证,生成物位于被忽略的 `.local/`
|
||||||
- 标准启动路径:`$env:RUN_START_COMMAND="1"; .\init.ps1`
|
- 标准启动路径:`$env:RUN_START_COMMAND="1"; .\init.ps1`
|
||||||
- 标准验证路径:`.\init.ps1`
|
- 标准验证路径:`.\init.ps1`
|
||||||
- 当前 blocker:T-217 无阻塞。真实 VLM 服务地址、模型、设备级测试凭证、成本上限
|
- 当前 blocker:T-218 实现无代码阻塞;当前真机确认页缺少已配置收货地址,因此
|
||||||
和数据留存尚未确认;当前只支持单 SKU/JPEG;候选探针截图要求 Android 11/API 30+
|
真实提交 smoke 必须按合约阻塞,不能为测试自动添加地址。真实 VLM 服务地址、模型、
|
||||||
|
设备级测试凭证、成本上限和数据留存尚未确认;当前只支持单 SKU/JPEG;候选探针
|
||||||
|
截图要求 Android 11/API 30+
|
||||||
|
|
||||||
## 当前目录
|
## 当前目录
|
||||||
|
|
||||||
@@ -149,7 +154,8 @@
|
|||||||
## 任务摘要
|
## 任务摘要
|
||||||
|
|
||||||
- 已完成:T-001 至 T-004、T-101 至 T-104、T-201 至 T-217。
|
- 已完成:T-001 至 T-004、T-101 至 T-104、T-201 至 T-217。
|
||||||
- 下一步:T-218 单次订单提交与订单回读,然后实现 T-219 付款提醒。
|
- 进行中:T-218 单次订单提交与订单回读。
|
||||||
|
- 下一步:T-219 Admin 待付款提醒与端到端验收。
|
||||||
|
|
||||||
## 当前可运行内容
|
## 当前可运行内容
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
---
|
||||||
|
id: T-218
|
||||||
|
title: 单次订单提交与订单回读
|
||||||
|
phase: 2
|
||||||
|
deps:
|
||||||
|
- T-217
|
||||||
|
status: DOING
|
||||||
|
created: 2026-07-28
|
||||||
|
context_ref: 1e87b62
|
||||||
|
work_branch: null
|
||||||
|
write_paths:
|
||||||
|
- docs/tasks/T-218.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
|
||||||
|
- 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-217 已在手机和后端保存同一授权的 READY dry-run,并停在拼多多确认订单页。本任务
|
||||||
|
消费该 READY 一次:确认地址和付款边界安全后最多点击一次“提交订单”,随后只读回到
|
||||||
|
订单列表,以订单号和下单时间完成对账。
|
||||||
|
|
||||||
|
“HTTP 请求失败”“App 进程退出”和“页面没有及时跳转”都不能被解释为未提交。服务端
|
||||||
|
一旦发出单次提交围栏,App 在任何恢复路径都只能对账或转人工,不能再次点击。系统
|
||||||
|
只创建待付款订单,不选择、确认或执行支付。
|
||||||
|
|
||||||
|
## 关联需求与交互
|
||||||
|
|
||||||
|
- `FR-21`:Admin 授权绑定不可变任务、candidate 和人工 review。
|
||||||
|
- `FR-22`:一个授权最多创建一个拼多多订单,结果不确定时先对账。
|
||||||
|
- `US-010` / `IX-011`:设备只提交一次、回读订单号和时间,Admin 付款提醒由
|
||||||
|
T-219 完成。
|
||||||
|
|
||||||
|
## 冻结合约
|
||||||
|
|
||||||
|
### 提交前置条件
|
||||||
|
|
||||||
|
1. App 本地加密 READY 与后端 `order_dry_runs.status=READY` 必须引用同一 task、
|
||||||
|
execution、generation、authorization、command hash、SKU、数量、单价、总额和
|
||||||
|
evidence hash;租约有效、任务未取消且后端在线。
|
||||||
|
2. 每次不可逆动作前重新读取当前确认订单页。标题锚点、颜色、尺码、数量、商品金额/
|
||||||
|
应付总额必须继续满足 T-217;页面必须能确定性看到已配置的收货地址。出现
|
||||||
|
“添加收货地址”“请选择地址”、地址缺失或地址不可判定时停止。
|
||||||
|
3. App 不修改地址、优惠券、运费、服务或付款方式。最终动作必须是唯一、可见、启用
|
||||||
|
且文本精确为“提交订单”的无障碍节点;出现“立即支付”“确认支付”“免密支付”
|
||||||
|
“先用后付”或其他自动扣款含义时停止。OCR 只读结果不能产生点击。
|
||||||
|
4. App 先用幂等请求从后端创建 `order_submission`。服务端事务内把该 authorization
|
||||||
|
永久置为可能已消费并返回唯一 submission ID。响应不确定时只查询/重放同一请求,
|
||||||
|
不生成新的 ID。
|
||||||
|
5. App 收到 submission ID 后,先在 Keystore-backed 状态保存
|
||||||
|
`CLICK_ASSUMED`,再调用唯一的 `submitOrderOnce` accessibility 动作。保存成功即
|
||||||
|
认为点击可能已发生;即使实际点击尚未发出就崩溃,恢复后也只能对账或转人工。
|
||||||
|
|
||||||
|
### 单次动作与恢复
|
||||||
|
|
||||||
|
1. 一个 authorization、dry-run 和 submission 都有数据库唯一约束;提交 start
|
||||||
|
的同 key/body 重放返回原记录,不同 body 或第二个 submission 返回冲突。
|
||||||
|
2. accessibility 层不得暴露通用文本点击或坐标点击给订单提交状态机。
|
||||||
|
`submitOrderOnce` 只接受当前 submission fence,并在进程内原子消费;它不能点击
|
||||||
|
支付、验证码、风控、地址或未知页面。
|
||||||
|
3. 点击前、点击返回后、HTTP 超时、网络断开、进程重启或页面未知均不允许第二次
|
||||||
|
`submitOrderOnce`。本地状态只有
|
||||||
|
`READY -> CLICK_ASSUMED -> RECONCILING -> RECONCILED/MANUAL_REVIEW` 单向迁移。
|
||||||
|
4. 点击后若进入收银台/支付页,只允许系统返回或只读导航到订单列表;不点击任何付款
|
||||||
|
控件。验证码、风控或系统权限页立即转人工。
|
||||||
|
|
||||||
|
### 订单回读与唯一对账
|
||||||
|
|
||||||
|
1. App 在受控预算内进入当前拼多多账号的订单列表/待付款列表,只读取最近订单,不
|
||||||
|
滚动无界历史。对每个可见项读取订单编号、平台显示的下单时间、状态、标题、SKU、
|
||||||
|
数量和金额;WebView 语义树折叠时可用端上 OCR 只读降级。
|
||||||
|
2. 可归属订单必须同时满足:待付款状态、标题有界锚点一致、颜色/尺码唯一匹配、数量
|
||||||
|
和总额精确一致、下单时间位于服务端 `fenced_at` 前后有界窗口。订单编号必须来自
|
||||||
|
明确“订单编号”标签,不能把物流号、商品 ID 或页面其他数字当成订单号。
|
||||||
|
3. 只有一个订单满足全部条件时,App 上传受控截图并幂等回传订单号、平台下单时间、
|
||||||
|
订单字段和 evidence。后端将 submission 置为 `RECONCILED`、authorization 置为
|
||||||
|
`CONSUMED`、execution 的 `order_submitted=true`,并写审计事件。
|
||||||
|
4. 零个或多个可能订单、字段缺失/冲突、时间无法解析、订单状态不是待付款或证据上传
|
||||||
|
失败时进入 `MANUAL_REVIEW`/`RECONCILING`。这不是可重试提交错误;后续只能重新
|
||||||
|
读取订单列表或由人员对账。
|
||||||
|
5. 订单号属于受限业务数据:只保存到鉴权后端和 App 加密状态,不写普通日志、不发给
|
||||||
|
VLM、不进入截图文件名。T-219 才在 Admin 详情显示待付款提醒。
|
||||||
|
|
||||||
|
## 数据模型与 API
|
||||||
|
|
||||||
|
v11:
|
||||||
|
|
||||||
|
- `order_submissions`:每个 authorization/dry-run 唯一一行,保存 submission ID、
|
||||||
|
command/dry-run hash、`fenced_at`、状态、预期 SKU/数量/金额、回读订单号/时间、
|
||||||
|
evidence 和错误码;
|
||||||
|
- `device_order_submission_requests`:按 device + operation + idempotency key 保存
|
||||||
|
请求 hash 和稳定结果;
|
||||||
|
- task events 增加 `ORDER_SUBMISSION_FENCED`、`ORDER_SUBMISSION_RECONCILED` 和
|
||||||
|
`ORDER_SUBMISSION_MANUAL_REVIEW`;
|
||||||
|
- `order_authorizations` 增加不可逆消费中/已消费状态;`execution_outcomes` 仅在
|
||||||
|
唯一对账成功后允许 `order_submitted=true`。
|
||||||
|
|
||||||
|
设备接口:
|
||||||
|
|
||||||
|
- `POST /api/v1/tasks/{task_id}/order-submissions/start`
|
||||||
|
- `POST /api/v1/tasks/{task_id}/order-submissions/{submission_id}/reconcile`
|
||||||
|
- `POST /api/v1/tasks/{task_id}/order-submissions/{submission_id}/manual-review`
|
||||||
|
|
||||||
|
所有写接口都要求 BUYER bearer、原 claim token、execution/generation、command 和
|
||||||
|
dry-run 身份及 `Idempotency-Key`。start 只接受 READY;reconcile/manual-review
|
||||||
|
只接受同一已经围栏的 submission。
|
||||||
|
|
||||||
|
## 验收要点
|
||||||
|
|
||||||
|
- [ ] start 只有 READY、有效租约、未取消和完全一致的命令/金额可成功。
|
||||||
|
- [ ] 同一授权最多一个 submission;响应丢失、重启和重复请求不能产生第二次点击。
|
||||||
|
- [ ] 缺少地址、自动扣款语义、非精确“提交订单”或页面不确定时 fail closed。
|
||||||
|
- [ ] 点击前持久化 `CLICK_ASSUMED`;恢复路径只有订单回读,没有重新提交。
|
||||||
|
- [ ] 订单列表只读回读必须唯一匹配订单号、下单时间、SKU、数量、金额和待付款状态。
|
||||||
|
- [ ] 零个/多个匹配转人工且仍禁止重新提交;证据和事件可审计。
|
||||||
|
- [ ] 代码路径不包含支付点击,订单号不进日志/VLM。
|
||||||
|
- [ ] v11 migration、Go test/race/vet、Android test/Debug/Release 和根验证通过。
|
||||||
|
- [ ] 真机至少证明缺地址/危险付款语义会阻塞;只有具备受控地址和明确待付款语义时
|
||||||
|
才允许执行真实单次提交 smoke。
|
||||||
|
|
||||||
|
## 边界
|
||||||
|
|
||||||
|
- 不自动选择或修改收货地址、优惠券、运费、服务和付款方式。
|
||||||
|
- 不点击“立即支付/确认支付/免密支付/先用后付”,不保存支付凭证。
|
||||||
|
- 不用 VLM、OCR、旧 ordinal、坐标或模糊文本决定不可逆点击。
|
||||||
|
- 不因未找到订单而重按提交;人工付款提醒和 Admin 展示属于 T-219。
|
||||||
|
|
||||||
|
## 执行记录
|
||||||
|
|
||||||
|
- 2026-07-28:在 T-217 实现提交 `1e87b62` 后领取。冻结服务端一次性提交围栏、
|
||||||
|
点击前 `CLICK_ASSUMED` 持久化、恢复只对账、订单列表唯一匹配和自动付款禁区。
|
||||||
Reference in New Issue
Block a user