diff --git a/docs/02-requirements.md b/docs/02-requirements.md
index c3a685b..d0389bd 100644
--- a/docs/02-requirements.md
+++ b/docs/02-requirements.md
@@ -104,8 +104,10 @@ US-004 的试选后人工确认已从 MVP 删除。US-006 在 MVP 为:系统
等于任务值。缺失、重复、禁用、前缀碰撞、读回不一致都停止,不选相近项。
- **F-006 三道价格闸门**:价格只从规格面板和订单确认页读取,金额使用十进制字符串。
1. 选中目标规格后读取当前 SKU 单价,计算 `单价 × 数量`,不得超过授权最高总价。
- 2. 设置并复核数量后再次读取同一规格与单价;规格必须仍相同,单价必须与闸门一完全相等。
- 3. 订单确认页核对规格、数量与应付总额;总额不得超过授权最高总价。
+ 2. 设置并复核数量后再次核对同一规格,并唯一读取规格面板的目标数量总额;总额不得超过授权
+ 最高总价。多件优惠可能非线性,不用闸门一金额乘数量猜总额,也不要求目标数量总额等于闸门一。
+ 3. 订单确认页核对规格、数量与应付总额;应付总额必须与闸门二面板总额严格相等,且再次不超过
+ 授权最高总价。
任一道读不到、有歧义或不通过都停止并转人工,不从详情页、搜索页或按钮文字凑价格。
- 同一设备会话连续完成上述步骤;不退出商品再等采购服务确认,也不把旧截图或旧页面读数当作
当前提交依据。
@@ -127,13 +129,13 @@ US-004 的试选后人工确认已从 MVP 删除。US-006 在 MVP 为:系统
### 结果、证据与异常
-- **F-007**:按步骤回传实际规格、两次规格面板价格、数量读回、确认页总额、判定、时间和截图。
+- **F-007**:按步骤回传实际规格、闸门一单价、数量读回、闸门二面板总额、确认页总额、判定、时间和截图。
截图是内部审计证据,不是提交前审批前置。
- 内部系统允许上传规格面板与订单确认页的原始截图,截图中可保留页面已显示的地址和手机号;只允许
已认证设备显式上传、已登录管理员查看。完整 XML 只留采购工具本机,不上传;地址/手机号不解析为
业务字段或日志;外部支付页、支付凭据永不上传。
- **F-011**:至少区分设备未连接、版本失配、商品打不开、面板打不开、规格不匹配、价格不可读、
- 两次价格不一致、数量复核失败、金额超上限、确认页不一致、提交控件不唯一、围栏失败、页面识别
+ 规格漂移、数量复核失败、闸门二总额不可读或超上限、确认页与闸门二不一致、提交控件不唯一、围栏失败、页面识别
失败、安全校验、外部支付交接和超时。
- 运行时拼多多 App 版本与已取证版本不一致时停止领取真机任务,提示重新取证。
- 订单明确创建后展示截图、商品、规格、数量和授权金额;人在拼多多付款后手工标记完成。
diff --git a/docs/04-architecture.md b/docs/04-architecture.md
index 1dc0633..3fa9541 100644
--- a/docs/04-architecture.md
+++ b/docs/04-architecture.md
@@ -81,9 +81,9 @@ MVP 只做任务自带商品链接的 A 路径。创建任务与开始采购分
│ 3. 按维度精确选择并读回颜色、尺码
│ 4. 【闸门一】读 SKU 单价;单价×数量不得超过最高总价
│ 5. 设置数量并精确读回
- │ 6. 【闸门二】重读规格与单价;规格不变且价格等于闸门一
+ │ 6. 【闸门二】重读规格、数量与面板总额;总额不超最高总价
│ 7. 进入订单确认页
- │ 8. 【闸门三】规格/数量一致,应付总额不超最高总价
+ │ 8. 【闸门三】规格/数量一致,应付总额等于闸门二且不超最高总价
│ 9. 上传验证摘要并申请服务端提交围栏
│ 10. 仅在 click_permitted=true 且提交控件唯一时点击一次
│ 11. 回传观察结果;不确定时只调和,不重试
@@ -135,14 +135,20 @@ T-103 最新真机证据表明:拼多多 `8.17.0`、goods_id `937122477375`、
| 闸门 | 当前页面 | 判据 | 拒绝条件 |
| --- | --- | --- | --- |
| 一 | 规格面板,选中目标规格后 | 单价唯一可读;`单价 × 授权数量 <= 最高总价` | 不可读、有歧义或超上限 |
-| 二 | 规格面板,数量读回后 | 颜色、尺码仍正确;重读单价与闸门一完全相等 | 规格漂移或价格变化 |
-| 三 | 订单确认页 | 规格、数量正确;应付总额唯一可读且不超最高总价 | 任一不一致、不可读或超上限 |
+| 二 | 规格面板,数量读回后 | 颜色、尺码仍正确;目标数量面板总额唯一可读且不超最高总价 | 规格/数量漂移、总额不可读/有歧义或超上限 |
+| 三 | 订单确认页 | 规格、数量正确;应付总额唯一可读、严格等于闸门二且不超最高总价 | 任一不一致、不可读、有歧义或超上限 |
金额一律使用十进制字符串和十进制定点运算,不用浮点数。价格只从规格面板和订单确认页读取;
详情正文、搜索卡片、底部购买/提交按钮的数字不作为价格来源。
-闸门一与闸门二发生在同一设备会话中。它们用于发现选择或设置数量造成的页面变化,不需要管理员
-在中间确认。旧截图、缓存值和发布前 dry-run 都不能替代这次实时读取。
+2026-08-06 的拼多多 `8.17.0` 真机证据证明同一规格的多件优惠是非线性的:数量 1 时规格面板顶部
+当前金额为 `12.88`,数量 2 时变为 `32.76`,而不是 `12.88 × 2`。因此闸门一仍是设置数量前的单价
+预检,闸门二必须读取设置后的**面板总额** `gate2_panel_total_price` 并直接比较最高总价;不得把
+Gate1 乘数量、不得要求 Gate2 等于 Gate1,也不得把底部“提交订单 ¥...”金额作为价格候选或兜底。
+Gate3 再要求确认页应付总额与 Gate2 面板总额严格相等,这比只检查上限多一道跨页防漂移约束。
+
+闸门一与闸门二发生在同一设备会话中,不需要管理员在中间确认。旧截图、缓存值和发布前 dry-run
+都不能替代这次实时读取。
### B 路径(V2)
@@ -176,8 +182,8 @@ T-103 最新真机证据表明:拼多多 `8.17.0`、goods_id `937122477375`、
1. **一次性授权有效且服务端提交围栏已建立**:围栏把授权、任务、领取和本次验证摘要原子绑定到
唯一 `order_submission`;明确响应包含 `click_permitted=true`。
-2. **闸门二通过**:目标规格未漂移,第二次规格面板单价等于第一次。
-3. **闸门三通过**:确认页规格、数量正确,应付总额不超过授权最高总价。
+2. **闸门二通过**:目标规格和数量未漂移,目标数量面板总额唯一可读且不超过授权最高总价。
+3. **闸门三通过**:确认页规格、数量正确,应付总额严格等于闸门二面板总额,且不超过授权最高总价。
4. **提交控件唯一**:文本精确等于“提交订单”,可点击祖先唯一。
围栏请求超时、断网、冲突或响应不明时不得点击。围栏建立后:
@@ -246,7 +252,7 @@ CREATE TABLE purchase_attempts (
claim_generation INTEGER NOT NULL,
status TEXT NOT NULL,
gate1_unit_price TEXT,
- gate2_unit_price TEXT,
+ gate2_panel_total_price TEXT,
quantity_read INTEGER,
confirm_amount TEXT,
failure_code TEXT,
@@ -296,7 +302,7 @@ CREATE TABLE order_submissions (
attempt_id TEXT NOT NULL REFERENCES purchase_attempts(id),
status TEXT NOT NULL, -- FENCED | SUBMITTED | RECONCILIATION_REQUIRED | MANUAL_RESOLVED
gate1_unit_price TEXT NOT NULL,
- gate2_unit_price TEXT NOT NULL,
+ gate2_panel_total_price TEXT NOT NULL,
quantity_read INTEGER NOT NULL,
confirm_amount TEXT NOT NULL,
created_at TEXT NOT NULL,
@@ -458,7 +464,7 @@ DRAFT / PENDING / NEEDS_MANUAL ─管理员取消(围栏前)→ CANCELED
| 页面结构随版本变化 | 旧选择器误点新页面 | 每条判据先真机取证,记录 App 版本、截图、XML、goods_id |
| 购买语义入口才打开面板 | 能力范围易扩散 | 只批准证据绑定的精确唯一入口;每种文案单独取证 |
| 当前价与原价/按钮价混杂 | 读错价格 | 限定已取证结构和语义;价格只在面板/确认页读,歧义即停 |
-| 单趟页面状态变化 | 数量或促销导致价格变化 | 同一趟两次读规格面板价,再以确认页总额兜底 |
+| 单趟页面状态变化 | 数量或促销导致金额非线性变化 | 同一趟读 Gate1 单价与 Gate2 面板总额,再要求确认页总额与 Gate2 严格相等 |
| WiFi ADB / 双通道 | 断连或操作错设备 | serial 必填;USB/WiFi 同设备或身份不明时 fail closed |
| 不可逆动作超时 | 可能已创建订单 | 服务端围栏 + 点击一次 + 只调和,不重试 |
| 双端契约漂移 | 静默不兼容 | [api.md](api.md) 唯一权威;契约改动跑完整双端门禁 |
diff --git a/docs/05-coding-rules.md b/docs/05-coding-rules.md
index df74def..5fe61be 100644
--- a/docs/05-coding-rules.md
+++ b/docs/05-coding-rules.md
@@ -45,8 +45,9 @@
- 价格**只在规格面板(闸门一 / 二)和订单确认页(闸门三)读**。
- **不从商品详情页正文、搜索结果卡片或任何其他位置读价格。**
- 读不到就转人工,**不用别处的数字凑合**。
-- 同一趟设置并复核数量后,闸门二重读的规格必须不变、单价必须与闸门一完全一致;授权锁定的是
- 最高总价而不是旧观察价。价格变化即停。
+- 同一趟设置并复核数量后,闸门二重读的规格必须不变,并唯一读取目标数量的规格面板总额,直接
+ 验证不超授权最高总价;后续闸门三应付总额必须与该面板总额严格相等并再次不超上限。2026-08-06
+ 真机已证明多件优惠非线性,不得用闸门一金额乘数量猜 Gate2 总额,也不得要求 Gate2 等于 Gate1。
- 图片搜索(V2)的唯一产出是 `goods_id`,同样不读价。
### 1.4 安全与隐私
diff --git a/docs/06-tasks.md b/docs/06-tasks.md
index 0282eec..3b910c9 100644
--- a/docs/06-tasks.md
+++ b/docs/06-tasks.md
@@ -60,7 +60,7 @@ Phase 是里程碑分组,不是整段串行栅栏。推荐波次:
| T-102 | 验证按链接打开商品详情页 | T-101 | canonical goods 链接进入对应商品;前台包与 goods_id 有证据 |
| T-103 | 验证受控规格面板、精确选择与 SKU 单价 | T-102, T-110, T-111 | 精确唯一入口、维度内等值选择/读回、防前缀碰撞、当前价唯一读取;隔离 capability 不含数量/确认/提交 |
| T-104 | 验证规格选择能力安全退出 | T-103 | 完成选择/读价/截图后可关闭面板或退出;不进入确认页、不提交 |
-| T-105 | 验证数量设置、读回与闸门二 | T-104 | 先只读取证并由人确认,再设置数量、精确读回并复核规格/单价;不一致即停 |
+| T-105 | 验证数量设置、读回与闸门二 | T-104 | 先只读取证并由人确认,再设置数量、精确读回并复核规格/目标数量面板总额;规格或数量不一致、总额不可读/超上限即停 |
| T-106 | dry-run:确认页与闸门三取证 | T-105 | 只读采集导航前、确认页、最终控件及一次人工 Back 状态;agent 不执行页面动作 |
| T-107 | 固化确认页与提交控件安全判据 | T-106 | 只点已取证导航控件一次;最终控件只读观察;一次 Back;静态不可达提交 |
| T-110 | 批准证据绑定的受控规格入口 | T-103 no-go 决策 | 仅批准拼多多 8.17.0 已取证的精确唯一“快要抢光”,不泛化 |
diff --git a/docs/07-user-stories.md b/docs/07-user-stories.md
index 8997ae6..6c942f3 100644
--- a/docs/07-user-stories.md
+++ b/docs/07-user-stories.md
@@ -58,7 +58,7 @@
- 启动前同时校验采购服务、ADB 设备和已取证拼多多版本;任一不满足则不启动。
- 顶部始终显示会话状态;当前任务、图片、滚动日志和倒序采购记录实时更新。
-- 精确规格、两次单价、数量读回、确认页总额或提交控件任一不合格时停止该任务。
+- 精确规格、闸门一单价、数量读回、闸门二面板总额、确认页同额校验或提交控件任一不合格时停止该任务。
- 围栏明确成功后只点一次“提交订单”;系统绝不点击付款。
- 连续轮询失败达到阈值自动停止;停止轮询不取消正在执行或已围栏的任务。
diff --git a/docs/08-interaction-checklist.md b/docs/08-interaction-checklist.md
index b6439b7..3a5c807 100644
--- a/docs/08-interaction-checklist.md
+++ b/docs/08-interaction-checklist.md
@@ -57,7 +57,8 @@
### IX-006 待付款核对与标记完成
-- 页面显示商品、目标与实际规格、数量、授权上限、两次单价、确认页总额和三闸门内部证据;MVP
+- 页面显示商品、目标与实际规格、数量、授权上限、闸门一单价、闸门二面板总额、确认页同额校验和
+ 三闸门内部证据;MVP
没有提交后结果截图类型,不把确认页图片冒充订单结果图。
- 首屏警示:“订单已创建,系统尚未付款。请在拼多多人工核对并付款。”
- “标记为已付款并完成”只写系统状态,不打开支付页面、不触发手机操作。
diff --git a/docs/api.md b/docs/api.md
index 8eb110c..fa7535b 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -326,17 +326,21 @@ claim/renew 的格式错误固定为 `400 {"error":"invalid_request"}`,超限
"selected_color": "黑色CHA(纯棉)",
"selected_size": "M(建议100-115)",
"gate1_unit_price": "12.88",
- "gate2_unit_price": "12.88",
+ "gate2_panel_total_price": "32.76",
"quantity_read": 2,
- "confirm_page_amount": "25.76",
+ "confirm_page_amount": "32.76",
"submit_control_match_count": 1
}
```
服务端在一个事务中校验:任务/版本/claim/attempt 一致;授权有效未消费且字段等于任务快照;
-规格与授权相等;数量相等;两个单价相等;计算金额及确认页金额均不超过 `total_price_cap`;提交控件
-计数为一;此前不存在该授权或 attempt 的 submission。随后创建唯一 `order_submission`,授权转
-`FENCED`,任务保持不可重领。
+规格与授权相等;数量相等;闸门一单价预检通过;闸门二目标数量面板总额不超过 `total_price_cap`;
+确认页金额严格等于闸门二面板总额且再次不超过上限;提交控件计数为一;此前不存在该授权或 attempt
+的 submission。随后创建唯一 `order_submission`,授权转 `FENCED`,任务保持不可重领。
+
+`gate2_panel_total_price` 是目标数量下规格面板顶部证据角色的总额,不是单价。拼多多多件优惠可能
+非线性,禁止用 `gate1_unit_price × quantity_read` 推导它,也禁止继续用旧字段名
+`gate2_unit_price` 承载总额。底部“提交订单 ¥...”文字不属于价格来源。
首次明确成功响应:
@@ -443,6 +447,7 @@ events/fail/fence/result 或完整 `ResultSink`。T-304/T-306 必须通过 `Dura
| `select_sku_options()` | 维度 → 精确值 | 选中态摘要 | 维度内唯一匹配并读回 |
| `read_sku_unit_price()` | 已确认规格面板 | 十进制单价 | 排除原价、按钮价和歧义候选 |
| `set_quantity_and_readback()` | 授权数量 | 实际数量 | 精确读回,否则停 |
+| `read_sku_panel_total_price()` | 已读回目标数量 | 十进制面板总额 | 只读证据绑定的顶部当前金额;排除底部提交按钮金额和歧义候选 |
| `go_to_order_confirm()` | 已通过闸门二 | 确认页摘要 | 后续真机任务取证后才实现 |
| `submit_order_once()` | 不可伪造的首次 `SubmissionPermit` | 观察结果 | 许可、闸门、唯一控件全校验;点前持久化;绝不重试 |
diff --git a/docs/current-state.md b/docs/current-state.md
index f1b69fe..7adb3e1 100644
--- a/docs/current-state.md
+++ b/docs/current-state.md
@@ -30,7 +30,7 @@
已取证的固定尺码 reveal、精确 M 选择、规格面板单价 `12.88` 与一次 Back 已进入生产 Flow 并完成
真机人工验收;T-104 已把同商品详情页安全退出收紧为版本绑定、连续两帧稳定判据,数量/确认页/提交仍未开放。
- 测试:采购服务已覆盖登录、建单、授权、详情/证据、设备身份、迁移、原子 claim/renew 与竞态;
- 采购工具 311 项离线单元测试(全部 mock,不连接真机)。
+ 采购工具 314 项离线单元测试(全部 mock,不连接真机)。
- 数据:受保护迁移已落到 `00005_task_claims.sql`。旧两趟模型已移除;开始采购会锁定任务快照并签发
一次性授权,领取会创建唯一 attempt/claim、HMAC claim token 与有界租约。T-211 已统一 title、SKU、
goods_id 与金额的双端 wire 上限,并证明最坏合法 claim 响应小于 32 KiB。仓库不含业务实例数据。
@@ -90,9 +90,10 @@
正文的固定白名单失败阶段码;`sku_entry` 动态页面误判已按最新真机证据修复,覆盖点击中心的浮窗
会保持零点击,入口失败也已细分为前置、发现、点击和面板后置验证四个固定子阶段。服务端后续顺序已收紧为
T-210 → T-205 → T-206 → T-207 → T-208。
-- T-105 阶段一已实现数量 1/2 两态 screenshot/XML/App/设备摘要的纯只读取证并通过 311 项客户端测试;
- 当前等待人工分别准备同商品、同规格的数量 1 和数量 2 两态并确认。两态人验前不写数量点击、读回
- 或 Gate2 生产判据。
+- T-105 阶段一数量 1/2 两态 screenshot/XML/App/设备摘要已完成四项人工确认。真机证明同一规格
+ 数量 1 面板金额为 `12.88`、数量 2 为 `32.76`,多件优惠非线性;Gate2 已改为唯一读取目标数量
+ 面板总额并直接比较最高总价,后续 Gate3 必须与其严格相等。阶段二正在从两态证据实现一次加号、
+ 精确读回和安全退出;底部“提交订单”金额继续排除且禁止点击。
- T-303 已完成并通过三重审查;T-304 的轮询会话、配置页和固定双 Tab 主界面已通过两轮独立代码审计,
当前 255 项客户端测试与根门禁通过,继续保持 `DOING` 等原生 Windows DPI、主题、高对比度、
Narrator 和纯键盘人工验收。客户端后续按依赖推进 T-306/T-307/T-308,再与 T-305 汇合到
@@ -200,9 +201,16 @@ T-105 阶段一只读取证命令如下。脚本不打开页面,也不点击
.\client\.venv\Scripts\python.exe client\scripts\capture_quantity_gate2_spike.py --serial 192.168.0.173:5555 --goods-id 937122477375 --state target --declared-quantity 2 --output-dir "$env:LOCALAPPDATA\cmbuyer\artifacts\T-105\quantity-target-937122477375" --timeout 10 --adb D:\Portable\adb\adb.exe
```
-两次成功目录只保存在本机。人工需核对截图/XML 确实对应数量 1/2、目标颜色和尺码、规格面板单价,
+两次成功目录只保存在本机。人工需核对截图/XML 确实对应数量 1/2、目标颜色和尺码、规格面板顶部金额,
并确认过程中未进入确认/提交/支付页且未创建订单;确认前 T-105 保持 `DOING`。
+2026-08-06 两态已经完成上述人工确认。初态目录为
+`%LOCALAPPDATA%\cmbuyer\artifacts\T-105\quantity-initial-937122477375-20260806-v3`,目标态目录为
+`%LOCALAPPDATA%\cmbuyer\artifacts\T-105\quantity-target-937122477375-20260806`。数量节点精确读回
+`1 → 2`,唯一加号的 `content-desc` 为“增加数量”,目标颜色和 M 均未漂移;顶部当前金额
+`12.88 → 32.76`。旧 `gate2_unit_price` 语义已废止,T-210/T-205 消费前必须把 API/存储迁移为
+`gate2_panel_total_price`,迁移未完成不得建立提交围栏。
+
## 关键背景
本项目是 `cmroubao`(Go 后端 + Android AccessibilityService)与 `cmpdd`
diff --git a/docs/design/desk-execution.html b/docs/design/desk-execution.html
index feca171..0ce8178 100644
--- a/docs/design/desk-execution.html
+++ b/docs/design/desk-execution.html
@@ -470,6 +470,7 @@
颜色分类—
尺码 / 数量—
闸门一单价—
+ 闸门二面板总额—
金额上限—
提交围栏未建立
@@ -583,7 +584,7 @@
const task = {
id: 'CB-20260803-0042',
product: '纯棉圆领短袖 T 恤(原型假数据)',
- color: '白色', sizeQty: 'XL / 2 件', gate1Price: 'CNY 32.50', cap: 'CNY 80.00'
+ color: '白色', sizeQty: 'XL / 2 件', gate1Price: 'CNY 32.50', gate2Total: 'CNY 65.00', cap: 'CNY 80.00'
};
const records = [
{
@@ -604,15 +605,15 @@
id:'REC-DEMO-0038', taskId:'CB-20260803-0038', title:'标签打印纸补货(原型假数据)', collectedAt:'2026-08-03T10:06:42+08:00',
status:'WAITING_PAYMENT', spec:'白色 | 50×30 | 1 件', cap:'CNY 50.00', submission:'SUB-DEMO-0038 · SUBMITTED',
note:'已明确创建待付款订单,自动化已停止,等待人核对后自行付款。', evidence:['订单确认页内部原始截图(内联假证据)'],
- timeline:['10:04:22 同一趟精确选择规格','10:05:10 两次价格与数量复核通过','10:05:36 获得唯一围栏许可','10:06:42 明确创建待付款订单'],
+ timeline:['10:04:22 同一趟精确选择规格','10:05:10 Gate1 单价、Gate2 面板总额与 Gate3 确认金额通过','10:05:36 获得唯一围栏许可','10:06:42 明确创建待付款订单'],
result:'已创建待付款订单:白色 | 50×30 | CNY 46.00 | 1 件', resultNote:'系统只创建待付款订单,付款始终由人完成。'
},
{
id:'REC-DEMO-0032', taskId:'CB-20260803-0032', title:'仓库打包胶带(原型假数据)', collectedAt:'2026-08-03T09:18:05+08:00',
status:'NEEDS_MANUAL', spec:'透明 | 45mm | 4 件', cap:'CNY 55.00', submission:'未建立',
- note:'设置数量后规格面板价格与闸门一不一致,已在围栏前转人工。', evidence:[],
- timeline:['09:16:40 打开商品','09:17:22 匹配透明 / 45mm','09:18:05 价格闸门二不通过,停止自动流程'],
- result:'未采购:闸门一 CNY 12.00 | 闸门二 CNY 13.50', resultNote:'没有建立围栏、创建订单或付款。'
+ note:'目标数量的规格面板总额超过授权上限,已在围栏前转人工。', evidence:[],
+ timeline:['09:16:40 打开商品','09:17:22 匹配透明 / 45mm','09:18:05 闸门二面板总额超限,停止自动流程'],
+ result:'未采购:闸门一单价 CNY 12.00 | 闸门二面板总额 CNY 58.00 > 上限 CNY 55.00', resultNote:'没有建立围栏、创建订单或付款。'
}
].sort((a, b) => b.collectedAt.localeCompare(a.collectedAt));
const recordStatus = {
@@ -627,7 +628,7 @@
let detailRequestId = 0;
const baseSteps = {
idle: [],
- single: ['核对一次性授权并打开商品', '精确选择颜色分类与尺码', '闸门一:读取 SKU 单价并校验上限', '设置数量、读回并执行闸门二', '确认页执行闸门三与控件唯一校验', '申请服务端提交围栏', '首次许可后持久化并内部点击一次', '调和同一提交结果']
+ single: ['核对一次性授权并打开商品', '精确选择颜色分类与尺码', '闸门一:读取 SKU 单价并校验上限', '设置数量、读回并读取闸门二面板总额', '确认页执行闸门三同额与控件唯一校验', '申请服务端提交围栏', '首次许可后持久化并内部点击一次', '调和同一提交结果']
};
const scenarios = {
not_ready: { tone:'critical', title:'web 服务不可达', text:'未开始轮询。检查本地网络和服务地址;已完成的本地证据会保留待补传。', web:'bad', device:'ok', version:'ok', leg:'未就绪', legTone:'critical', action:'开始轮询', enabled:false, reason:'web 服务未就绪,不能领取任务。', session:'未启动', step:'连接检查', kind:'idle', active:-1, countdown:'—', fail:'1 / 3' },
@@ -637,8 +638,8 @@
claimed: { tone:'info', title:'已领取管理员授权的采购任务', text:'任务字段与最高总价已锁定;当前只准备打开目标商品,尚未建立提交围栏。', web:'ok', device:'ok', version:'ok', leg:'单趟 · 已领取', legTone:'info', action:'真机步骤执行中', enabled:false, reason:'当前任务已开始,停止轮询只应阻止下一次领取,不能硬取消本任务。', session:'运行中', step:'核对授权与商品', kind:'single', active:0, countdown:'暂停', fail:'0 / 3', lease:'04:48' },
selecting: { tone:'info', title:'正在精确选择颜色与尺码', text:'只在已取证维度容器内精确唯一匹配并读回;缺失、重复或版本变化立即停止。', web:'ok', device:'ok', version:'ok', leg:'单趟 · 选择规格', legTone:'info', action:'真机步骤执行中', enabled:false, reason:'当前受控步骤不能被硬取消。', session:'运行中', step:'精确选择规格', kind:'single', active:1, countdown:'暂停', fail:'0 / 3', lease:'04:18' },
gate1: { tone:'info', title:'闸门一:读取 SKU 单价', text:'当前规格单价必须唯一可读,单价乘数量不得超过管理员授权的最高总价。', web:'ok', device:'ok', version:'ok', leg:'单趟 · 闸门一', legTone:'info', action:'安全校验进行中', enabled:false, reason:'价格不可读或超上限时立即停止。', session:'运行中', step:'闸门一:读取 SKU 单价', kind:'single', active:2, countdown:'暂停', fail:'0 / 3', lease:'03:58' },
- quantity_gate2: { tone:'info', title:'数量复核与闸门二', text:'数量必须读回为 2;目标规格不能漂移,第二次单价必须等于闸门一 CNY 32.50。', web:'ok', device:'ok', version:'ok', leg:'单趟 · 闸门二', legTone:'info', action:'安全校验进行中', enabled:false, reason:'数量、规格或价格变化都停止。', session:'运行中', step:'数量读回与闸门二', kind:'single', active:3, countdown:'暂停', fail:'0 / 3', lease:'03:31' },
- confirm_gate3: { tone:'caution', title:'确认页与闸门三', text:'正在核对规格、数量、应付总额与提交控件唯一;此时没有点击许可。', web:'ok', device:'ok', version:'ok', leg:'单趟 · 闸门三', legTone:'caution', action:'安全校验进行中', enabled:false, reason:'没有服务端围栏许可,绝不能点击提交订单。', session:'运行中', step:'闸门三:核对应付总额', kind:'single', active:4, countdown:'暂停', fail:'0 / 3', lease:'02:58' },
+ quantity_gate2: { tone:'info', title:'数量复核与闸门二', text:'数量必须读回为 2;目标规格不能漂移,面板总额 CNY 65.00 必须唯一可读且不超过 CNY 80.00。', web:'ok', device:'ok', version:'ok', leg:'单趟 · 闸门二', legTone:'info', action:'安全校验进行中', enabled:false, reason:'数量、规格、总额歧义或超限都停止。', session:'运行中', step:'数量读回与闸门二', kind:'single', active:3, countdown:'暂停', fail:'0 / 3', lease:'03:31' },
+ confirm_gate3: { tone:'caution', title:'确认页与闸门三', text:'正在核对规格、数量、应付总额严格等于闸门二面板总额,并确认提交控件唯一;此时没有点击许可。', web:'ok', device:'ok', version:'ok', leg:'单趟 · 闸门三', legTone:'caution', action:'安全校验进行中', enabled:false, reason:'没有服务端围栏许可,绝不能点击提交订单。', session:'运行中', step:'闸门三:核对应付总额', kind:'single', active:4, countdown:'暂停', fail:'0 / 3', lease:'02:58' },
fencing: { tone:'caution', title:'正在申请服务端提交围栏', text:'等待首次明确的 click_permitted。超时、冲突、网络失败或响应不明都不会点击。', web:'ok', device:'ok', version:'ok', leg:'单趟 · 申请围栏', legTone:'caution', action:'等待围栏响应', enabled:false, reason:'申请中禁止取消、关闭或换 key 重复申请。', session:'运行中', step:'申请唯一提交围栏', kind:'single', active:5, countdown:'暂停', fail:'0 / 3', lease:'02:31' },
fence_failed: { tone:'critical', title:'未获得首次明确点击许可', text:'围栏失败或响应不明:没有点击提交订单。只核查同一幂等键,不能直接重试。', web:'bad', device:'ok', version:'ok', leg:'单趟 · 未获许可', legTone:'critical', action:'打开围栏核查说明', enabled:true, safeAction:'review', reason:'只核查围栏状态,不触发提交。', session:'已停止', step:'核查幂等键', kind:'single', active:5, countdown:'—', fail:'1 / 3', submission:'围栏状态未知 · 幂等键 DEMO-FENCE-042' },
fenced: { tone:'caution', title:'围栏已建立,只核对同一提交', text:'submission_id 已固定。内部流程至多点击一次;界面不提供提交、重领、放弃或重试。', web:'ok', device:'ok', version:'ok', leg:'单趟 · 已围栏', legTone:'caution', action:'打开同一提交核查说明', enabled:true, safeAction:'review', reason:'只能查看与调和同一提交记录。', session:'受控执行', step:'调和订单结果', kind:'single', active:7, countdown:'暂停', fail:'0 / 3', lease:'01:49', submission:'SUB-DEMO-0042 · FENCED' },
@@ -646,7 +647,7 @@
uncertain: { tone:'critical', title:'订单可能已创建,结果不明确', text:'保持金额预留和永久围栏,只核查 SUB-DEMO-0042;禁止重新领取、释放授权或再次点击。', web:'ok', device:'ok', version:'ok', leg:'RECONCILIATION_REQUIRED', legTone:'critical', action:'打开人工核查说明', enabled:true, safeAction:'review', reason:'核查不会发起新的下单。可另行导出假证据摘要。', session:'已停止', step:'人工核查同一提交', kind:'single', active:7, countdown:'—', fail:'0 / 3', submission:'SUB-DEMO-0042 · 结果不明确' },
security: { tone:'critical', title:'检测到安全校验,已停止', text:'不绕过验证码、风控、人脸或短信。若已围栏,只调和同一提交;围栏前转人工。', web:'ok', device:'ok', version:'ok', leg:'待人工 · 安全校验', legTone:'critical', action:'打开人工核查说明', enabled:true, safeAction:'review', reason:'只显示核查说明,不提供绕过或继续。', session:'已停止', step:'等待人工处理', kind:'single', active:7, countdown:'—', fail:'1 / 3', submission:'SUB-DEMO-0042 · RECONCILIATION_REQUIRED' },
payment_handoff: { tone:'critical', title:'进入外部支付交接,已停止', text:'订单可能已创建、支付未完成。不会读取或输入支付凭据,也没有“继续付款”按钮。', web:'ok', device:'ok', version:'ok', leg:'待人工 · 外部支付', legTone:'critical', action:'打开人工核查说明', enabled:true, safeAction:'paymentInfo', reason:'只显示人工核查与付款边界。', session:'已停止', step:'人工核查同一提交', kind:'single', active:7, countdown:'—', fail:'0 / 3', submission:'SUB-DEMO-0042 · HANDED_OFF' },
- manual: { tone:'caution', title:'任务已转人工:闸门二价格变化', text:'闸门一 CNY 32.50,数量设置后重读 CNY 35.00。围栏未建立,没有创建订单;需管理员核查后重置。', web:'ok', device:'ok', version:'ok', leg:'NEEDS_MANUAL', legTone:'caution', action:'导出假诊断摘要', enabled:true, safeAction:'export', reason:'导出只生成本地假文本,不含完整 XML、页面全文或敏感字段。', session:'继续轮询其他任务', step:'当前任务已移交', kind:'single', active:3, countdown:'00:11', fail:'0 / 3', submission:'未建立' },
+ manual: { tone:'caution', title:'任务已转人工:闸门二总额超限', text:'目标数量面板总额 CNY 85.00 超过最高总价 CNY 80.00。围栏未建立,没有创建订单;需管理员核查后重置。', web:'ok', device:'ok', version:'ok', leg:'NEEDS_MANUAL', legTone:'caution', action:'导出假诊断摘要', enabled:true, safeAction:'export', reason:'导出只生成本地假文本,不含完整 XML、页面全文或敏感字段。', session:'继续轮询其他任务', step:'当前任务已移交', kind:'single', active:3, countdown:'00:11', fail:'0 / 3', submission:'未建立' },
failed_stop: { tone:'critical', title:'连续失败达到阈值,轮询已停止', text:'最近三次均为服务连接失败。检查设置和网络;修复后重新开始普通轮询,不会重试任何提交点击。', web:'bad', device:'ok', version:'ok', leg:'自动停止', legTone:'critical', action:'前往配置', enabled:true, safeAction:'settings', reason:'先修复连接;不会自动恢复轮询。', session:'已停止', step:'等待修复', kind:'idle', active:-1, countdown:'—', fail:'3 / 3', count:4 }
};
const sessionControls = {
@@ -834,7 +835,9 @@
$('task-id').textContent = hasTask ? task.id : '—'; $('lease').textContent = s.lease || '—';
$('product').textContent = hasTask ? task.product : '暂无商品;轮询会在安全就绪后领取一条任务';
$('color').textContent = hasTask ? task.color : '—'; $('size-qty').textContent = hasTask ? task.sizeQty : '—';
- $('gate1-price').textContent = hasTask && ['gate1','quantity_gate2','confirm_gate3','fencing','fence_failed','fenced','waiting_payment','uncertain','security','payment_handoff','manual'].includes($('scenario').value) ? task.gate1Price : '—'; $('price-cap').textContent = hasTask ? task.cap : '—';
+ $('gate1-price').textContent = hasTask && ['gate1','quantity_gate2','confirm_gate3','fencing','fence_failed','fenced','waiting_payment','uncertain','security','payment_handoff','manual'].includes($('scenario').value) ? task.gate1Price : '—';
+ $('gate2-total').textContent = hasTask && ['quantity_gate2','confirm_gate3','fencing','fence_failed','fenced','waiting_payment','uncertain','security','payment_handoff'].includes($('scenario').value) ? task.gate2Total : '—';
+ $('price-cap').textContent = hasTask ? task.cap : '—';
$('submission').textContent = s.submission || '未建立';
$('preview-empty').hidden = hasTask; $('product-preview-image').hidden = !hasTask;
$('preview-source').textContent = hasTask ? '来源:内部原始商品截图(内联假证据)' : '来源:尚无可信图片';
diff --git a/docs/design/web-task-detail.html b/docs/design/web-task-detail.html
index e7b25b0..e569081 100644
--- a/docs/design/web-task-detail.html
+++ b/docs/design/web-task-detail.html
@@ -26,22 +26,22 @@
待开始
任务已保存,但尚未授权采购工具领取或创建订单。
- 创建不等于授权请返回任务列表勾选任务,并点击“开始采购(只创建待付款订单)”。
- 商品
- goods_id 937122477375
- 颜色 / 尺码
- 黑色CHA(纯棉) / M(建议100-115)
- 数量
- 2 件
- 最高总价
- ¥30.00
+ 创建不等于授权请返回任务列表勾选任务,并点击“开始采购(只创建待付款订单)”。
- 商品
- goods_id 937122477375
- 颜色 / 尺码
- 黑色CHA(纯棉) / M(建议100-115)
- 数量
- 2 件
- 最高总价
- ¥40.00
已授权,等待采购工具领取
管理员的开始采购动作已锁定任务字段和最高总价。
- 一次性授权已创建允许采购工具按本任务创建一笔待付款订单;不授权付款。
- 授权编号
- AUTH-018-V2
- 任务版本
- 2
- 最高总价
- ¥30.00
- 提交围栏
- 尚未建立
本状态没有“机器选对了吗”按钮。规格与价格将在设备执行时实时校验。
+ 一次性授权已创建允许采购工具按本任务创建一笔待付款订单;不授权付款。
- 授权编号
- AUTH-018-V2
- 任务版本
- 2
- 最高总价
- ¥40.00
- 提交围栏
- 尚未建立
本状态没有“机器选对了吗”按钮。规格与价格将在设备执行时实时校验。
- - 已打开目标商品App 8.17.0;goods_id 已核对
- 已精确选择规格黑色CHA(纯棉) / M(建议100-115)
- 闸门一通过SKU 单价 ¥12.88;预计总额 ¥25.76
- 数量已读回2 件;正在执行闸门二
- 尚未建立提交围栏不会点击提交订单
无需中途人工确认任一读数变化或有歧义,系统会停止并转人工。
+ - 已打开目标商品App 8.17.0;goods_id 已核对
- 已精确选择规格黑色CHA(纯棉) / M(建议100-115)
- 闸门一通过SKU 单价 ¥12.88;数量前预检通过
- 闸门二通过数量读回 2 件;面板总额 ¥32.76 ≤ ¥40.00
- 尚未建立提交围栏不会点击提交订单
无需中途人工确认任一读数变化或有歧义,系统会停止并转人工。
- 禁止重试唯一提交记录 SUB-018-5A7C 已占用本授权;关闭页面也不会释放。
| 门禁 | 读取值 | 结论 |
|---|
| 闸门一 | ¥12.88 × 2 = ¥25.76 | 通过 |
| 闸门二 | 规格不变;¥12.88 | 通过 |
| 闸门三 | 确认页 ¥25.76 ≤ ¥30.00 | 通过 |
| 提交控件 | 精确唯一 1 个 | 通过 |
+ 禁止重试唯一提交记录 SUB-018-5A7C 已占用本授权;关闭页面也不会释放。
| 门禁 | 读取值 | 结论 |
|---|
| 闸门一 | 单价 ¥12.88;数量前预检通过 | 通过 |
| 闸门二 | 规格 / 数量不变;面板总额 ¥32.76 ≤ ¥40.00 | 通过 |
| 闸门三 | 确认页 ¥32.76 = 闸门二;≤ ¥40.00 | 通过 |
| 提交控件 | 精确唯一 1 个 | 通过 |
@@ -51,12 +51,12 @@
-
+
围栏前需要人工处理
系统已经停止,未申请围栏、未点击提交订单。
- 闸门二未通过闸门一 ¥12.88,数量设置后重读 ¥13.20;不使用新价格继续。
- 失败阶段
- 规格面板 · 闸门二
- 原因码
- SKU_PRICE_CHANGED
- 安全处置
- 停止并保留证据
- 可用动作
- 人工核查后重置为待开始或取消
+ 闸门二未通过目标数量面板总额 ¥42.00 超过最高总价 ¥40.00;围栏未建立。
- 失败阶段
- 规格面板 · 闸门二
- 原因码
- GATE2_TOTAL_OVER_CAP
- 安全处置
- 停止并保留证据
- 可用动作
- 人工核查后重置为待开始或取消
人工付款事实已记录系统没有执行付款,也没有读取支付凭据。
@@ -66,7 +66,7 @@
diff --git a/docs/routes.md b/docs/routes.md
index d1201b1..40c4959 100644
--- a/docs/routes.md
+++ b/docs/routes.md
@@ -75,7 +75,7 @@
1. 任务要求:商品链接 / goods_id、颜色、尺码、数量、最高总价、版本。
2. 开始采购授权:授权 id、授权人、锁定任务版本、创建/有效期、当前状态。
3. 设备执行:attempt、设备、App 版本、步骤时间线和失败 code。
-4. 三道闸门:两次规格面板单价、规格/数量读回、确认页总额与判定。
+4. 三道闸门:闸门一规格面板单价、规格/数量读回、闸门二面板总额、确认页同额校验与判定。
5. 内部截图:三道闸门已批准的规格面板/确认页证据;只经受保护端点读取。MVP 不存在提交后结果
截图类型,不展示外部支付页,也不把 Gate3 图片冒充结果图。
6. 提交围栏:submission id、是否首次明确许可、唯一点击和调和记录。
diff --git a/docs/tasks/T-105.md b/docs/tasks/T-105.md
index e67d862..caefc86 100644
--- a/docs/tasks/T-105.md
+++ b/docs/tasks/T-105.md
@@ -12,6 +12,16 @@ needs_device: true
needs_human_review: true
write_paths:
- docs/tasks/T-105.md
+ - docs/02-requirements.md
+ - docs/04-architecture.md
+ - docs/05-coding-rules.md
+ - docs/api.md
+ - docs/06-tasks.md
+ - docs/07-user-stories.md
+ - docs/08-interaction-checklist.md
+ - docs/routes.md
+ - docs/design/desk-execution.html
+ - docs/design/web-task-detail.html
- client/src/cmbuyer_client/pdd/quantity_gate2_spike.py
- client/src/cmbuyer_client/pdd/quantity_gate2.py
- client/src/cmbuyer_client/pdd/quantity_gate2_runner.py
@@ -23,7 +33,7 @@ write_paths:
- docs/current-state.md
---
-
+
## 问题 / 背景
T-104 将把规格选择、闸门一读价、原始截图和安全退出固化为受控能力。T-105 先对当前真机数量控件和读回位置取证,再实现规格面板内的数量设置、精确读回与闸门二;不进入确认页、不接触最终提交。
@@ -42,8 +52,8 @@ T-104 将把规格选择、闸门一读价、原始截图和安全退出固化
2. 阶段二从本项目证据提取最小 fixture,固化数量显示、增减控件、选中规格和价格节点的精确唯一结构;版本/包/面板/规格/控件任一失配都零点击。
3. QuantityGate2Flow 接受 T-104 Gate1Observation、目标数量和最高总价。数量必须为服务端任务正整数,不接受浮点、字符串猜测或超上限值。
4. 每次数量修改只点击证据证明的唯一控件一次,并等待明确后置条件;超时或结果不明不得重试该次点击。达到目标前每一步都重新定位和读回,不使用裸坐标或缓存节点。
-5. 闸门二重新读取颜色、尺码、数量和规格面板单价;颜色/尺码必须等于目标,数量精确等于请求,gate2 单价逐字规范化后等于 gate1 单价,并用十进制运算确认单价×数量不超最高总价。
-6. 成功结果是不可变 Gate2Observation,包含请求/实际规格、quantity_read、gate1/gate2_unit_price、max_total_price、规格面板原始 screenshot_path 与 UTC captured_at。
+5. 闸门二重新读取颜色、尺码、数量和规格面板目标数量总额;颜色/尺码必须等于目标,数量精确等于请求,`gate2_panel_total_price` 必须唯一可读且以十进制比较不超最高总价。2026-08-06 真机证明多件优惠非线性,数量 1 为 12.88、数量 2 为 32.76,因此不得把 gate1 金额乘数量、不得要求 gate2 等于 gate1,也不得用底部“提交订单”金额作为候选或兜底。后续闸门三必须与该 Gate2 面板总额严格相等并再次不超上限,否则转人工。
+6. 成功结果是不可变 Gate2Observation,包含请求/实际规格、quantity_read、gate1_unit_price、gate2_panel_total_price、max_total_price、规格面板原始 screenshot_path 与 UTC captured_at;旧 `gate2_unit_price` 语义已被真机证据否定,后续服务端契约与存储必须在 T-210/T-205 前改名迁移,禁止以旧字段名承载总额。
7. 失败、价格不可读/多候选、规格漂移、数量不符或超价都安全停止并使用 T-104 一次性安全退出;Back 结果不明不重试。
8. 能力与 T-103/T-104 分层:T-103 不能反向导入本任务;本任务不暴露确认页导航、通用 click、最终提交控件、围栏或付款能力。
@@ -51,7 +61,7 @@ T-104 将把规格选择、闸门一读价、原始截图和安全退出固化
- 先证据后实现,执行记录包含两态截图/XML/hash、版本、设备、goods_id 与人工确认。
- 离线覆盖数量边界、每步单击一次、后置条件、超时不重试、节点缺失/重复、SystemUI/锁屏/版本漂移。
-- 覆盖闸门二规格不变、价格严格相等、Decimal 总价、数量读回及所有失败分支零确认页动作。
+- 覆盖闸门二规格不变、数量读回、Gate2 面板总额唯一可读、Decimal 上限比较、非线性优惠反例,以及节点缺失/重复/漂移和所有失败分支零确认页动作;静态禁止把 Gate1 乘数量、底部“提交订单”金额或旧 `gate2_unit_price` 当作 Gate2 事实。
- 静态证明 T-103 不导入数量,本任务不可达确认页、围栏、submit_order_once 或付款。
- 真机人工确认目标数量、规格、两次价格、截图、一次安全退出,且未进入确认/提交/支付页、未创建订单。
- client 全量 unittest、compileall、完整 init、上下文校验、Vikunja 导出与 diff-check 通过;agent 保持 DOING 等人工验收。
@@ -76,6 +86,24 @@ T-104 将把规格选择、闸门一读价、原始截图和安全退出固化
### 2026-08-05T10:08:24Z · ila
2026-08-05 T-105 阶段一只读取证代码完成并推送,代码 commit `994b6c8`。新增 `quantity_gate2_spike.py` 与 CLI:只接受显式 serial、固定 goods_id 937122477375、人工声明 initial=1 / target=2 和全新目录;每次重新核验 PKG110 / Android 16 / PDD 8.17.0 / PDD 前台 / 1080×2376,只调用 `takeScreenshot` 与 `dumpWindowHierarchy`,保存 screenshot/XML/App 摘要/manifest,前后台或版本漂移不发布。接口与静态测试证明无 intent、click、swipe、Back、数量修改、确认、提交或支付能力。专项 13/13、客户端全量 311/311、compileall、agent-context、完整 `init.ps1` 均通过。下一步必须由人分别准备同一商品、黑色CHA(纯棉)+M(建议100-115) 的数量 1 和数量 2 两态并运行只读取证;两态人工确认前不实现数量点击、readback 或 Gate2 判据。任务保持 DOING。
+
+### 2026-08-06T01:00:27Z · ila
+
+2026-08-06 T-105 阶段一两态真机证据与四项人工确认完成。设备 PKG110 / Android16 / WiFi,PDD 8.17.0,goods_id 937122477375,目标规格均为黑色CHA(纯棉)+M(建议100-115)。
+
+初态目录:`C:\Users\ila20\AppData\Local\cmbuyer\artifacts\T-105\quantity-initial-937122477375-20260806-v3`;captured_at `2026-08-06T00:53:00.023935+00:00`;screenshot SHA-256 `959c62f90d05a4d2a8e212b0286d7ad7e958e00e56915ddf733ce7fd9b11f9c0`;XML SHA-256 `f31d15ef0763d9685448aba0086b6f67b459e4991b5d01a5daae333dd3b9c16d`。人工确认数量1、目标规格、金额12.88。
+
+目标态目录:`C:\Users\ila20\AppData\Local\cmbuyer\artifacts\T-105\quantity-target-937122477375-20260806`;captured_at `2026-08-06T00:55:30.898374+00:00`;screenshot SHA-256 `1954d9f8dbbc80b73ef5b93ae941c0501baa3f35c3f040e0cd4ef9723eb40057`;XML SHA-256 `e6ffcdc71119b8e0ac35e135afac54517f9c28c4d9da1070168901dce1988b81`。人工确认数量2、目标规格不变、金额32.76。
+
+人工四项确认:两态数量分别1/2;颜色尺码均未变化;金额分别12.88/32.76;未进入确认/支付页、未点击“提交订单”、未创建订单。
+
+XML 允许字段摘要:数量节点为唯一 clickable/enabled EditText,`1 [480,752][561,827]` → `2 [480,750][561,825]`;唯一加号为 clickable/enabled ImageView、content-desc 精确“增加数量”、初态 bounds `[567,752][645,827]`、目标态 `[567,750][645,825]`;顶部价格角色 `快卖完 ¥12.88` → `快卖完 ¥32.76`;底部 `提交订单 ¥...` 继续排除且禁止点击。真机事实证明多件优惠非线性,Gate2 必须读取目标数量面板总额并与最高总价比较,不能继续用旧 gate2_unit_price 等值假设。任务进入阶段二,仍保持 DOING。
+
+### 2026-08-06T01:04:25Z · ila
+
+2026-08-06 T-105 初态首次只读取证阻塞取证:人工已确认规格面板为目标颜色/尺码/数量1,并关闭 OPPO 游戏助手视觉层;`dumpsys window` 的 mCurrentFocus/mFocusedApp 与 `dumpsys activity activities` 的唯一 topResumedActivity 均为 `com.xunmeng.pinduoduo/.activity.NewPageActivity`,PDD versionName=8.17.0、PKG110、Android16、1080×2376 均正确,但 uiautomator2 `app_current()` 误报 `com.oplus.games`。根因是当前 adbutils 2.12.0 先执行 `dumpsys window windows`(本机 Android16 无对应焦点行),随后只识别旧式 `mResumedActivity:`,不识别实际 `topResumedActivity=`,最终错误退回 `dumpsys activity top` 的最后一项。
+
+最小修复计划:不放宽“PDD 必须前台”,也不接受 `com.oplus.games`。T-105 阶段一改用仅限 PKG110/Android16 的窄只读 foreground reader,执行固定的 adb 参数数组:指定 serial、shell、dumpsys activity activities;只接受恰好一个 `topResumedActivity` 且 package 精确为 PDD、activity 非空;缺失/重复/其他包/命令失败全部不截图、不发布。通用 shell 不暴露给 capturer,既有只读设备协议反而移除错误的 `app_current`。离线补齐真实 Android16 行、旧格式拒绝、重复/缺失/其他包/命令失败、前后漂移测试;验证后再重跑数量1初态。任务仍 DOING。
## 边界
@@ -83,15 +111,20 @@ T-104 将把规格选择、闸门一读价、原始截图和安全退出固化
- 必须先由人在拼多多 8.17.0 的目标规格面板分别准备初始数量与目标数量状态,只读采集并人工确认
screenshot/XML/版本/goods_id/规格/数量的对应性,之后才允许从本项目证据编写数量判据和点击代码。
不得从前序项目、旧 XML、控件常识、OCR、裸坐标或推理直接实现。
-- 数量控件、读回位置、规格选中态和两次价格都必须证据绑定且精确唯一。每次修改数量最多点击已批准
+- 数量控件、读回位置、规格选中态、Gate1 单价和 Gate2 面板总额都必须证据绑定且精确唯一。每次修改数量最多点击已批准
控件一次并等待明确后置条件;超时或结果不明不得重试同一次点击,不得缓存节点跨状态继续操作。
-- 闸门二必须重新核对颜色/尺码未漂移、数量精确等于任务、gate2 单价严格等于 gate1 单价,并以
- 十进制运算验证单价乘数量不超最高总价。价格只从规格面板读取,不用详情页或其他数字兜底。
+- 闸门二必须重新核对颜色/尺码未漂移、数量精确等于任务,并从证据绑定的规格面板顶部当前金额
+ 角色唯一读取 `gate2_panel_total_price`,以十进制直接验证其不超最高总价。2026-08-06 真机已证明
+ 多件优惠非线性:数量 1 为 `12.88`、数量 2 为 `32.76`;不得用 gate1 金额乘数量猜总额、不得要求
+ gate2 等于 gate1,也不得把底部“提交订单”金额作为候选或兜底。后续闸门三必须与 Gate2 面板总额
+ 严格相等且再次不超上限;任一不符即转人工。
- 只有规格、数量、价格、总价上限和原始截图全部通过后才返回不可变 Gate2Observation;它必须显式
携带 `screenshot_path` 与 UTC `captured_at`,不得让后续任务枚举目录或读取 manifest 猜证据。
- 任一判据失败、规格漂移、数量不符、价格不可读/多候选/变化或超价都停止前进,只能调用 T-104
已验证的一次性安全退出;Back 超时或结果不明不重试,不把“面板消失”当作退出成功。
- T-103/T-104 不得反向导入本任务。本任务不进入确认页、不观察或获取最终提交控件,不实现通用 click、
事件、证据上传、围栏或结果接口;不编写或引用点击“提交订单”的代码,不编写任何付款能力。
-- `needs_device: true`:agent 完成离线实现后仍保持 DOING。只有人确认真机数量、规格、两次价格、
+- 旧 `gate2_unit_price` 字段名已被本项目真机证据否定,不能用旧名字承载总额来掩盖语义变化;API 与
+ 服务端存储必须在 T-210/T-205 消费 Gate2 前迁移为 `gate2_panel_total_price`,迁移未完成时不得建立围栏。
+- `needs_device: true`:agent 完成离线实现后仍保持 DOING。只有人确认真机数量、规格、Gate1 单价与 Gate2 面板总额、
截图和安全退出,且未进入确认/提交/支付页、未创建订单,才可完成任务。