feat(t218): reconcile single order submissions

This commit is contained in:
QiuSW
2026-07-28 17:48:54 +08:00
parent 682cc7327c
commit a77d8be06d
32 changed files with 4306 additions and 79 deletions
+2 -1
View File
@@ -61,7 +61,8 @@ T-205 原子领取/租约状态机、T-206 Android 登录/有限离线、T-207
规格组合/价格核验均已完成。T-208 的原始候选观测、模型评估、确定性推荐、逐候选
结构化人工理由和修订历史也已完成。T-214 商品持久身份和重新定位指纹、T-215
Admin 候选确认、不可变待投递授权、T-216 设备命令可靠投递及 T-217 已授权商品
重新定位与订单 dry-run 均已完成;T-218 单次订单提交与订单回读正在开发。
重新定位与订单 dry-run、T-218 单次订单提交围栏和订单回读均已完成;下一项是
T-219 Admin 待付款提醒与端到端验收。
不得直接把候选链接或列表 ordinal 当成授权。
手机从管理后端领取任务并回传结果,VLM、拼多多自动化和人工确认在 App 本地完成。
T-206 增加有限离线执行;T-207 已复用 Roubao 端上 OpenAI 兼容适配器并加密本地 Key。
+1 -1
View File
@@ -11,7 +11,7 @@
| 执行方式 | 采购人员使用 Android App 操作拼多多;需求提取、动态词搜索、最多 5 个候选证据采集、匹配建议和人工确认停止点已可运行。 |
| 核心痛点 | 人工把图片和描述转成搜索词、逐条比较商品并记录结果,耗时且不一致。 |
| 验证范围 | 一台设备、一个管理身份、一个采购执行人员、拼多多单平台。 |
| 资金边界 | MVP 不提交订单、不支付,只验证到人工确认位置。 |
| 资金边界 | 仅在 Admin 明确授权和一次性围栏后创建待付款订单;系统不自动付款。 |
## 二、用户角色
+3
View File
@@ -650,6 +650,9 @@ local READY + backend READY + valid lease
submission fence 是 exactly-once 安全边界,不是“点击成功”回执。服务端创建围栏后,
任何进程恢复都假定订单可能已创建;宁可留下需要人工对账的未提交意图,也不能通过
重按产生重复订单。一个 authorization 和 dry-run 在数据库中只能对应一个 submission。
只有同一次未中断调用中新建本地 intent 并收到后台 `FENCED` 响应时才短暂持有点击
资格;磁盘恢复出的 intent 只能重放后台请求并进入对账。围栏已经存在后,即使 claim
租约到期也只继续对账,不恢复商品操作或提交资格。
不可逆动作前再次核对 T-217 全部商品字段,并要求明确可见的已配置地址和唯一
“提交订单”节点。地址缺失、金额变化、自动扣款方式或“立即支付/确认支付/免密支付/
+1 -1
View File
@@ -17,7 +17,7 @@
| IX-008 | US-006 | App/管理端错误状态 | 自动失败、取消、重试上传 | 显示结构化原因和恢复动作 | P0 | 已定 |
| IX-009 | US-008 | App 候选理由/管理端决策详情 | 接受、拒绝、改选或修正 | 保存逐候选结构化人工标签 | P1 | T-208 已实现 |
| IX-010 | US-009 | App 独立执行设置/同步状态 | 配置模式、离线执行或补报 | 授权内独立执行并可审计同步 | P0 | T-206 离线控制已实现,结果补报待 T-207 |
| IX-011 | US-010 | Admin 候选授权/App 订单执行 | 选择候选并授权、设备领取执行 | 创建一笔可对账的待付款订单并提醒人工付款 | P0 | T-215 至 T-217 已完成;T-218/T-219 待实现 |
| IX-011 | US-010 | Admin 候选授权/App 订单执行 | 选择候选并授权、设备领取执行 | 创建一笔可对账的待付款订单并提醒人工付款 | P0 | T-215 至 T-218 已完成;T-219 待实现 |
## IX-001 管理 Web 登录
+3
View File
@@ -334,6 +334,9 @@ App 唯一识别待付款订单并先上传受控 evidence 后,提交订单编
execution/generation、submission、期望快照、证据归属和幂等键;成功将 submission
置为 `RECONCILED`、authorization 置为 `CONSUMED` 并记录
`order_submitted=true`。订单编号不得进入 URL、日志、事件 message 或模型字段。
围栏创建后允许原 user/device/generation/claim token 在租约到期后完成该 submission
的对账,但任务必须仍未取消且 execution 未结束;该例外不适用于 start,也不产生
新的提交资格。
### `POST /api/v1/tasks/{task_id}/order-submissions/{submission_id}/manual-review`
+18 -15
View File
@@ -5,7 +5,7 @@
## 当前快照
- 日期:2026-07-28
- 阶段:T-218 单次订单提交与订单回读已领取,合约冻结中
- 阶段:T-218 单次订单提交与订单回读已完成;下一项 T-219
- Git:当前分支为 `main`;T-001 至 T-004、T-101 至 T-104、T-201 至 T-217
均按文档提交、实现提交的顺序纳入历史
- 生产代码:`android-buyer/` 已接入 Roubao Android 源码
@@ -17,10 +17,10 @@
- 本机 Android 工具:JDK 17.0.13、Command-line Tools 22.0、SDK 34、
Build Tools 34.0.0、Platform Tools/ADB 37.0.0;用户级 SDK 环境变量已设置
- Android Studio:未安装;`winget` 静默安装卡住后已终止,不阻塞命令行构建
- 测试:T-217 Android Debug/Release 单元测试与构建和根 `init.ps1` 通过;
Debug APK `1.4.14 (19)` 已覆盖安装到 PKG110
- 后端测试:T-217 运行 `go test ./...`、`go test -race ./...`、`go vet ./...`;
v10 migration 往返、带 dry-run 数据的降级保护及 start/ready HTTP 集成测试通过
- 测试:T-218 Android Debug/Release 单元测试与构建和根 `init.ps1` 通过;
Debug APK `1.4.15 (20)` 已覆盖安装到 PKG110
- 后端测试:T-218 运行 `go test ./...`、`go test -race ./...`、`go vet ./...`;
v11 migration 降级保护及 fence/replay/manual-review/reconcile HTTP 集成测试通过
- 原型:4 个管理 Web 页面和 7 个 Android 页面均可离线独立打开;Playwright
以 1440×900、390×844、360×800 验证 36 个页面/视口组合,无页面横向溢出、
脚本错误或外部请求,Android 可见交互控件均不小于 44px
@@ -76,9 +76,10 @@
唯一颜色/尺码、数量和预算重新核验 Admin 选择;确认页 WebView 折叠时使用端上
中文 OCR 做只读 fail-closed 证据提取。后端保存 v10 READY、截图、SKU、数量、
单价/总额和事件;无障碍动作集中不含订单提交或支付。
- T-218 目标:后端先创建一次性 submission fence,App 点击前持久化
`CLICK_ASSUMED`,最多点击一次精确“提交订单”;进程/网络不确定后只回读待付款
订单或转人工,绝不重复提交或点击支付。
- T-218 单次提交:后端先创建唯一 submission fence,App 点击前持久化
`CLICK_ASSUMED`,最多点击一次精确“提交订单”;进程/网络不确定和租约到期后只
回读待付款订单或转人工,绝不重复提交或点击支付。v11 保存围栏、幂等操作、订单号/
时间、证据和审计事件,唯一对账后才写 `order_submitted=true`。
- Workflow:纯 Kotlin runner 已支持步骤 timeout、最多 3 次 retry、安全阻塞、
用户停止和单 runner 并发拒绝;T-102 已接入搜索加有界候选采集五步
- TaskSource:严格 CLI 已生成并验证真实私有 ProbeTask;默认 APK 不含私有 fixture
@@ -92,11 +93,11 @@
- 离线执行:默认 30 分钟有限授权和 30 秒 best-effort heartbeat 已实现;PKG110
真机断开临时后端 95 秒后保持同一 execution,重连后滑动续期;到期持久安全停止,
RUNNING 不自动重新分配
- 测试设备:OnePlus PKG110,Android 16/API 36;已安装肉包 `1.4.14 (19)`;拼多多
- 测试设备:OnePlus PKG110,Android 16/API 36;已安装肉包 `1.4.15 (20)`;拼多多
`8.17.0 (81700)`
- 设备就绪:拼多多首页、文字/图片搜索、双列候选卡、详情截图和返回均已通过 8.17.0
真机验证;采购员已在 ColorOS 设置中手动启用肉包采购无障碍,APK 覆盖安装后授权
保持且服务已连接
真机验证;ColorOS 本次覆盖安装后移除了肉包采购无障碍,重新启用后服务已连接,
因此每次覆盖安装后都必须复核该系统授权
- 拼多多 8.17 兼容:结果页可识别新版显示查询词的文本搜索栏和“推荐、手机、女装”等
分类栏,也保留旧版“综合、销量、价格、筛选”识别;长任务搜索词的拼多多省略显示须
至少两个按序片段对应原词才通过。每次候选探针会重写本次搜索词,不复用已有结果页。
@@ -107,8 +108,9 @@
已用 CLI 真实导入并逐字段/图片哈希验证,生成物位于被忽略的 `.local/`
- 标准启动路径:`$env:RUN_START_COMMAND="1"; .\init.ps1`
- 标准验证路径:`.\init.ps1`
- 当前 blocker:T-218 实现无代码阻塞;当前真机确认页缺少已配置收货地址,因此
真实提交 smoke 必须按合约阻塞,不能为测试自动添加地址。真实 VLM 服务地址、模型、
- 当前 blocker:T-219 无代码阻塞;当前真机确认页缺少已配置收货地址且显示
“立即支付/先用后付”,T-218 已按合约证明不创建围栏、不点击。不能为测试自动添加
地址或跨过付款边界。真实 VLM 服务地址、模型、
设备级测试凭证、成本上限和数据留存尚未确认;当前只支持单 SKU/JPEG;候选探针
截图要求 Android 11/API 30+
@@ -143,6 +145,7 @@
| `docs/tasks/T-215.md` | DONE | Admin 按 candidate key 选择并创建不可变待投递授权 |
| `docs/tasks/T-216.md` | DONE | App 主动拉取并先加密落盘再确认同一条下单命令 |
| `docs/tasks/T-217.md` | DONE | 重新核对已授权商品并选择 SKU/数量,停在最终提交前 |
| `docs/tasks/T-218.md` | DONE | 单次提交围栏、最多一次提交动作和待付款订单唯一对账 |
| `docs/design/` | 已确认 | T-202 原型索引、4 个管理页和 7 个 Android 页面 |
| `deepseek总结.txt` | 已有 | 历史讨论摘要,不是正式需求权威 |
| `android-buyer/` | 已有 | Roubao `main` 固定 commit 的 Android 基线 |
@@ -153,8 +156,8 @@
## 任务摘要
- 已完成:T-001 至 T-004、T-101 至 T-104、T-201 至 T-217。
- 进行中:T-218 单次订单提交与订单回读。
- 已完成:T-001 至 T-004、T-101 至 T-104、T-201 至 T-218。
- 进行中:无。
- 下一步:T-219 Admin 待付款提醒与端到端验收。
## 当前可运行内容
+22 -10
View File
@@ -4,7 +4,7 @@ title: 单次订单提交与订单回读
phase: 2
deps:
- T-217
status: DOING
status: DONE
created: 2026-07-28
context_ref: 1e87b62
work_branch: null
@@ -119,15 +119,15 @@ dry-run 身份及 `Idempotency-Key`。start 只接受 READY;reconcile/manual-r
## 验收要点
- [ ] start 只有 READY、有效租约、未取消和完全一致的命令/金额可成功。
- [ ] 同一授权最多一个 submission;响应丢失、重启和重复请求不能产生第二次点击。
- [ ] 缺少地址、自动扣款语义、非精确“提交订单”或页面不确定时 fail closed。
- [ ] 点击前持久化 `CLICK_ASSUMED`;恢复路径只有订单回读,没有重新提交。
- [ ] 订单列表只读回读必须唯一匹配订单号、下单时间、SKU、数量、金额和待付款状态。
- [ ] 零个/多个匹配转人工且仍禁止重新提交;证据和事件可审计。
- [ ] 代码路径不包含支付点击,订单号不进日志/VLM。
- [ ] v11 migration、Go test/race/vet、Android test/Debug/Release 和根验证通过。
- [ ] 真机至少证明缺地址/危险付款语义会阻塞;只有具备受控地址和明确待付款语义时
- [x] start 只有 READY、有效租约、未取消和完全一致的命令/金额可成功。
- [x] 同一授权最多一个 submission;响应丢失、重启和重复请求不能产生第二次点击。
- [x] 缺少地址、自动扣款语义、非精确“提交订单”或页面不确定时 fail closed。
- [x] 点击前持久化 `CLICK_ASSUMED`;恢复路径只有订单回读,没有重新提交。
- [x] 订单列表只读回读必须唯一匹配订单号、下单时间、SKU、数量、金额和待付款状态。
- [x] 零个/多个匹配转人工且仍禁止重新提交;证据和事件可审计。
- [x] 代码路径不包含支付点击,订单号不进日志/VLM。
- [x] v11 migration、Go test/race/vet、Android test/Debug/Release 和根验证通过。
- [x] 真机至少证明缺地址/危险付款语义会阻塞;只有具备受控地址和明确待付款语义时
才允许执行真实单次提交 smoke。
## 边界
@@ -141,3 +141,15 @@ dry-run 身份及 `Idempotency-Key`。start 只接受 READY;reconcile/manual-r
- 2026-07-28:在 T-217 实现提交 `1e87b62` 后领取。冻结服务端一次性提交围栏、
点击前 `CLICK_ASSUMED` 持久化、恢复只对账、订单列表唯一匹配和自动付款禁区。
- 2026-07-28:合约提交 `682cc73`。实现 v11 submission/request 表、三条设备接口、
服务端唯一围栏和幂等对账;Android 加入确认页安全检查、加密恢复状态、单次点击
资格、待付款订单解析和有限唯一匹配。
- 2026-07-28:补强崩溃窗口:只有本次调用新建的 intent 可在收到围栏后获得点击
资格;恢复出的旧 intent、`CLICK_ASSUMED` 及其后状态永远不能重新点击。围栏已在
后端建立时,租约到期只允许继续订单列表对账。
- 2026-07-28:`go test ./...`、`go test -race ./...`、`go vet ./...`,
Android Debug/Release 单元测试和 APK 构建、根 `.\init.ps1` 全部通过。
- 2026-07-28:Debug `1.4.15 (20)` 真机阻断 smoke 通过。拼多多 8.17 确认页显示
“手动添加收货地址”“立即支付”和“先用后付”,肉包明确报告未创建提交围栏;
触发前后生产库 `order_submissions=0`,未点击下单或付款。因没有受控收货地址,
未执行真实订单提交。