fix(client): stop unsafe T-106 confirmation path

This commit is contained in:
QiuSW
2026-08-06 10:44:00 +08:00
parent b0b71d5a29
commit e93e2e8202
5 changed files with 46 additions and 45 deletions
@@ -1,4 +1,4 @@
"""采集 T-106 人工准备的确认页四态证据;不执行页面操作。"""
"""采集 T-106 人工准备的提交前来源态证据;不执行页面操作。"""
from __future__ import annotations
@@ -23,17 +23,14 @@ from cmbuyer_client.pdd.order_confirm_spike import (
def parse_arguments(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="采集 T-106 人工准备的确认页四态本机证据。")
parser = argparse.ArgumentParser(description="采集 T-106 人工准备的提交前来源态本机证据。")
parser.add_argument("--serial", required=True, help="ADB device serial;禁止自动选择。")
parser.add_argument("--goods-id", required=True, help="T-106 已批准的目标商品标识。")
parser.add_argument(
"--state",
required=True,
choices=DECLARED_STATES,
help=(
"人工声明状态:Gate2 后导航来源、确认页 Gate3、最终控件可见、"
"人工一次返回后的安全页。"
),
help="仅允许已取证的 Gate2 后提交前来源态;未证实的后续状态全部禁用。",
)
parser.add_argument("--output-dir", required=True, type=Path, help="全新本机证据目录;不得覆盖。")
parser.add_argument("--timeout", type=float, default=10.0, help="ADB 与只读设备 RPC 超时(秒)。")
@@ -97,13 +94,13 @@ def main(argv: list[str] | None = None) -> int:
)
except (DeviceConnectionError, OrderConfirmEvidenceError):
# 第三方异常可能带设备、页面正文或本机目录,命令行只输出固定摘要。
print("确认页四态只读取证失败:已停止,未发布本机证据目录。", file=sys.stderr)
print("T-106 只读取证失败:已停止,未发布本机证据目录。", file=sys.stderr)
return 1
except OSError:
print("确认页四态只读取证失败:无法发布本机证据目录。", file=sys.stderr)
print("T-106 只读取证失败:无法发布本机证据目录。", file=sys.stderr)
return 1
print("确认页四态只读取证完成。")
print("T-106 提交前来源态只读取证完成。")
print("人工复核:请在指定目录检查截图、XML、应用摘要和 manifest。")
return 0
@@ -1,4 +1,4 @@
"""T-106 确认页四态的纯只读取证;页面对应性只由人工确认。"""
"""T-106 提交前来源态的纯只读取证;页面对应性只由人工确认。"""
from __future__ import annotations
@@ -36,16 +36,11 @@ EXPECTED_GOODS_ID = "937122477375"
EXPECTED_DEVICE_MODEL = "PKG110"
EXPECTED_ANDROID_VERSION = "16"
EXPECTED_SCREEN_SIZE = (1080, 2376)
DECLARED_STATES = (
"gate2-navigation-source",
"confirm-gate3",
"submit-control-visible",
"returned-safe-page",
)
DECLARED_STATES = ("gate2-navigation-source",)
class OrderConfirmEvidenceError(RuntimeError):
"""T-106 四态证据未形成完整原子产物。"""
"""T-106 只读证据未形成完整原子产物。"""
class OrderConfirmEvidenceTimeoutError(OrderConfirmEvidenceError):
@@ -213,13 +208,13 @@ class OrderConfirmEvidenceCapturer:
raise
except (AdbTimeout, HTTPTimeoutError, TimeoutError) as error:
_clean_staging(staging)
raise OrderConfirmEvidenceTimeoutError("确认页四态只读取证超时,未发布证据。") from error
raise OrderConfirmEvidenceTimeoutError("T-106 只读取证超时,未发布证据。") from error
except (OSError, UnidentifiedImageError, ValueError) as error:
_clean_staging(staging)
raise OrderConfirmEvidenceError("确认页四态证据无法原子发布,未发布证据。") from error
raise OrderConfirmEvidenceError("T-106 证据无法原子发布,未发布证据。") from error
except Exception as error:
_clean_staging(staging)
raise OrderConfirmEvidenceError("确认页四态只读取证未完成,未发布证据。") from error
raise OrderConfirmEvidenceError("T-106 只读取证未完成,未发布证据。") from error
return OrderConfirmEvidenceResult(
output_directory=target,
+9 -3
View File
@@ -1,4 +1,4 @@
"""T-106 确认页四态纯只读取证的离线测试。"""
"""T-106 提交前来源态纯只读取证的离线测试。"""
from __future__ import annotations
@@ -229,8 +229,8 @@ class OrderConfirmEvidenceTests(unittest.TestCase):
timeout_seconds=2,
)
def test_all_four_human_states_publish_only_raw_read_evidence(self) -> None:
self.assertEqual(len(DECLARED_STATES), 4)
def test_only_approved_human_state_publishes_raw_read_evidence(self) -> None:
self.assertEqual(DECLARED_STATES, ("gate2-navigation-source",))
for state in DECLARED_STATES:
with self.subTest(state=state), TemporaryDirectory() as temporary:
adb = FakeAdbClient()
@@ -276,6 +276,9 @@ class OrderConfirmEvidenceTests(unittest.TestCase):
("", EXPECTED_GOODS_ID, DECLARED_STATES[0]),
(f" {SERIAL}", EXPECTED_GOODS_ID, DECLARED_STATES[0]),
(SERIAL, "958756616606", DECLARED_STATES[0]),
(SERIAL, EXPECTED_GOODS_ID, "confirm-gate3"),
(SERIAL, EXPECTED_GOODS_ID, "submit-control-visible"),
(SERIAL, EXPECTED_GOODS_ID, "returned-safe-page"),
(SERIAL, EXPECTED_GOODS_ID, "unknown"),
)
for serial, goods_id, state in scenarios:
@@ -465,6 +468,9 @@ class OrderConfirmCliAndStaticBoundaryTests(unittest.TestCase):
_namespace(serial=""),
_namespace(serial=f" {SERIAL}"),
_namespace(goods_id="958756616606"),
_namespace(state="confirm-gate3"),
_namespace(state="submit-control-visible"),
_namespace(state="returned-safe-page"),
_namespace(state="unknown"),
_namespace(output_dir=Path("")),
_namespace(timeout=0),
+13 -21
View File
@@ -12,7 +12,7 @@
## 当前快照
- 日期:2026-08-06
- 阶段:**Phase 1 · T-106 确认页只读取证与 Phase 2 安全服务端任务并行**
- 阶段:**Phase 1 · T-106 提交前页面事实重定值与 Phase 2 安全服务端任务并行**
- MVP 形态:手工填链接建单 → 批量“开始采购”并签发一次性授权 → 定时领取 → 同一趟精确
选规格 / 三道价格闸门 / 提交围栏 / 点击一次 → 待付款。管理员点击“开始采购”即授权桌面端
创建待付款订单;不再有试选后确认,系统绝不自动付款。
@@ -62,11 +62,11 @@
| 路径 | 状态 | 说明 |
| --- | --- | --- |
| `docs/` | 已有 | 项目规范化文档,本次已完整生成 |
| `docs/tasks/` | 已有(含 T-001~T-111、T-201~T-211、T-301~T-308、T-400~T-405) | T-103~T-105、T-303、T-211 已完成;T-304 代码完成后保持 DOING 等人工 UI 复核;T-106 已领取并完成只读取证代码,等待四态真机人工验收;双端围栏、真实提交、调和、打包与只读验收均已落成任务 |
| `docs/tasks/` | 已有(含 T-001~T-111、T-201~T-211、T-301~T-308、T-400~T-405) | T-103~T-105、T-303、T-211 已完成;T-304 代码完成后保持 DOING 等人工 UI 复核;T-106 第一态已证明不存在原计划的独立确认页导航,保持 DOING 等 Gate3 架构重定值;双端围栏、真实提交、调和、打包与只读验收均已落成任务 |
| `docs/design/` | 已有(6 个原型) | web 登录 / 建单 / 工作台 / 详情,desk 采购执行 / 配置;均已人工确认 |
| `scripts/` | 已有 | 上下文门禁、Vikunja 单向导出与 MCP 启动包装 |
| `admin/` | 已初始化 | Go 1.23+ / gin / SQLite,含建单/授权/详情/证据/设备身份与原子 claim/renew;不执行真机动作 |
| `client/` | 已初始化 | Python 3.11+、PySide6/uiautomator2、固定双 Tab 主界面、安全轮询、严格 HTTP/DPAPI/SQLite 恢复底座及受控规格选择/读价/数量 Gate2/安全退出;T-106 确认页四态仅开放纯只读取证,确认页生产导航和提交仍未开放 |
| `client/` | 已初始化 | Python 3.11+、PySide6/uiautomator2、固定双 Tab 主界面、安全轮询、严格 HTTP/DPAPI/SQLite 恢复底座及受控规格选择/读价/数量 Gate2/安全退出;T-106 只保留已取证的提交前来源态纯只读采集,最终提交仍未开放 |
| `init.ps1` / `init.sh` | 已完成 | 统一安装与离线验证入口;PowerShell 优先复用合规 venv,缺失时自动选择最高的 Python 3.11+,Unix 缺工具链明确失败 |
## 任务状态
@@ -225,27 +225,18 @@ T-105 阶段二生产验收已在人工确认的同一手机、拼多多 `8.17.0
项目所有者已确认数量精确为 2、颜色尺码未变、Gate1/Gate2 分别为 `12.88/32.76`、Gate2 截图正确、
一次 Back 回到同一商品详情,且未进入确认/提交/支付页、未创建订单。该命令只作已验运行记录,不再重跑。
T-106 已提供四态纯只读取证命令。每次运行都会重新核对设备、拼多多 `8.17.0`、前台包和
1080×2376 屏幕,只调用截图与 `compressed=false` XML;不会打开页面、点击、返回、滑动、输入或识别
确认页业务字段。四个输出目录必须均不存在,完整 XML 只留本机:
T-106 第一态只读取证已于 2026-08-06 完成。脚本重新核对设备、拼多多 `8.17.0`、前台包和
1080×2376 屏幕,只调用截图与 `compressed=false` XML;不会打开页面、点击、返回、滑动或输入:
```powershell
# 1. 人工准备:Gate2 已通过、尚未进入确认页;运行后再由人记录实际进入确认页的精确控件文本/容器/匹配数
.\client\.venv\Scripts\python.exe client\scripts\capture_order_confirm_spike.py --serial 192.168.0.173:5555 --goods-id 937122477375 --state gate2-navigation-source --output-dir "$env:LOCALAPPDATA\cmbuyer\artifacts\T-106\gate2-navigation-source-937122477375" --timeout 10 --adb D:\Portable\adb\adb.exe
# 2. 人工只点击已核对的确认页入口并停在 Gate3 页面;绝不点击最终“提交订单”
.\client\.venv\Scripts\python.exe client\scripts\capture_order_confirm_spike.py --serial 192.168.0.173:5555 --goods-id 937122477375 --state confirm-gate3 --output-dir "$env:LOCALAPPDATA\cmbuyer\artifacts\T-106\confirm-gate3-937122477375" --timeout 10 --adb D:\Portable\adb\adb.exe
# 3. 人工把最终“提交订单”控件准备为可见但不点击;记录精确文案、匹配数和启用态
.\client\.venv\Scripts\python.exe client\scripts\capture_order_confirm_spike.py --serial 192.168.0.173:5555 --goods-id 937122477375 --state submit-control-visible --output-dir "$env:LOCALAPPDATA\cmbuyer\artifacts\T-106\submit-control-visible-937122477375" --timeout 10 --adb D:\Portable\adb\adb.exe
# 4. 人工只返回一次并停手;结果不明时不再返回,直接停止
.\client\.venv\Scripts\python.exe client\scripts\capture_order_confirm_spike.py --serial 192.168.0.173:5555 --goods-id 937122477375 --state returned-safe-page --output-dir "$env:LOCALAPPDATA\cmbuyer\artifacts\T-106\returned-safe-page-937122477375" --timeout 10 --adb D:\Portable\adb\adb.exe
```
四态都必须由项目所有者本地核对截图/XML:规格、数量、Gate3 应付总额、最终控件精确文案/匹配数/
启用态、一次返回后的页面身份;同时确认未点击最终提交、未创建订单、未进入支付或安全验证页面。
满足全部人工验收前 T-106 保持 `DOING`,这些人工观察也不能在 T-106 中直接变成生产 selector。
证据与人工确认表明:该规格面板已经显示地址、支付方式、目标规格、数量 2、顶部 `32.76`,以及唯一
“提交订单 ¥32.76”;点击该红色控件会立刻创建待付款订单并进入付款界面,并不存在原计划中可安全
先进入的独立确认页。项目所有者确认本次未点击、未创建订单、未进入付款。第二至第四态命令已撤回,
脚本也只接受第一态;在独立架构决策重新定值 Gate3 前不得点击该控件,不得把按钮金额直接充当 Gate3,
也不得继续 T-107。T-106 保持 `DOING`。
## 关键背景
@@ -266,8 +257,9 @@ T-106 已提供四态纯只读取证命令。每次运行都会重新核对设
2. **拼多多页面结构随版本变化**,已观察到详情页无独立规格入口、价格节点被拆分等情况。
3. **授权卡死**:前序项目出现过 `EXECUTING` 授权永不推进导致任务锁死。本项目在 T-207
实现围栏前超时 / 放弃,在 T-208 实现围栏后调和;围栏后不得释放或重试。
4. **确认页能力仍未开放**:T-105 已按本项目真机证据开放数量 1→2、readback 与 Gate2;确认页导航、
Gate3 和最终控件仍必须依次等待 T-106/T-107 取证,不能从旧项目或推理直接实现。
4. **独立确认页前提已被推翻**:T-106 第一态证明当前规格面板上的“提交订单 ¥32.76”会直接创建
待付款订单并进入付款界面,没有原计划的安全确认页导航。Gate3 与提交四条件必须先做架构重定值;
当前禁止点击、禁止把按钮金额当 Gate3,也禁止继续 T-107。
5. **MVP 已收窄**:只做手工填链接、批量开始采购和单趟创建待付款订单。Excel、ERP、图搜、
批量顺序编排 / 暂停接管、订单自动核对、AI 辅助全部推到 V2(见 `06-tasks.md` 的
T-501~T-508)。
+12 -1
View File
@@ -18,7 +18,7 @@ write_paths:
- docs/current-state.md
---
<!-- BEGIN VIKUNJA EXPORT id=41 synced=2026-08-06T02:20:32Z sha256=3e585159a2607c63f54d72b84d9779699cce3cc79805ebc7c2bbd08cb80b815f -->
<!-- BEGIN VIKUNJA EXPORT id=41 synced=2026-08-06T02:43:02Z sha256=5c08daf987eb8174779832179c52853afbf7e28aa166053bb0bb75cb9cc1e0d0 -->
## 问题 / 背景
T-105 验证规格面板数量与闸门二后,下一步会进入更高风险的订单确认页。T-106 只由人手工准备确认页、最终提交控件可见态和一次返回后的页面,再用完全只读脚本采集真机事实;本任务不自动导航、不写确认页判据。
@@ -68,10 +68,21 @@ T-105 验证规格面板数量与闸门二后,下一步会进入更高风险
2026-08-06T02:20:23.748Z · Codex
T-106 四态纯只读取证代码已完成:新增 order_confirm_spike、capture_order_confirm_spike.py 与 16 项专项测试。静态 AST 证明生产模块/CLI 只允许 takeScreenshot、dumpWindowHierarchy,且不可达页面修改、确认页导航、提交、围栏或付款能力。client 全量 346 tests、compileall、validate_agent_context 与完整 init.ps1 均通过。任务保持 DOING,等待项目所有者依次人工准备并确认 Gate2 导航前、Gate3、最终控件可见、一次返回后四态;绝不点击最终提交。
### 2026-08-06T02:41:41Z · ila
2026-08-06T02:41:40.982Z · Codex
T-106 第一态真机事实(拼多多 8.17.0、PKG110/Android 16、goods_id 937122477375、WiFi):截图/XML/应用摘要与 manifest 完整,三项 SHA-256 均核对一致;页面显示目标颜色/M、数量 2、当前金额 32.76,并有唯一可见文本“提交订单 ¥32.76”。项目所有者确认该页仍是规格面板,点击红色“提交订单 ¥32.76”会立刻创建待付款订单并进入付款界面。因此原“四态”方案中独立确认页导航前提不成立;未点击该控件、未创建订单、未进入付款。立即禁止第二至第四态及任何该控件点击,T-106 保持 DOING,先重新定值 Gate3 架构,不能把底部按钮金额直接当 Gate3 或放宽提交四条件。截图 SHA-256=05531e020ac93048432d51554137fecf0879868ebad126771a041492cadca790;XML SHA-256=5ab31b45772e1b4e93976da5f029eeec1f5152207c2b8a75ee05ae5ce5673a7d;app 摘要 SHA-256=dcfd282da23bc5dee08e25446ed395c300c5ec9eb4d27d3c0b231a306641db50。
<!-- END VIKUNJA EXPORT -->
## 边界
- 2026-08-06 第一态真机证据与项目所有者确认推翻了“规格面板后还有独立确认页”的前提:当前规格
面板已经显示地址、支付方式和唯一“提交订单 ¥32.76”,点击会立刻创建待付款订单并进入付款界面。
因此当前只批准 `gate2-navigation-source` 只读取证;第二至第四态及该红色控件点击全部禁用。下方
原四态边界保留为被真机事实阻断的审计记录,不得继续执行;T-106 保持 `DOING`,必须先通过独立
架构决策重新定值 Gate3,且不得把底部按钮金额直接当 Gate3 或放宽提交订单四条件。
- 本任务只实现和运行只读取证能力:设备/App 摘要、`app_current`、screenshot、`compressed=false` XML、
hash 与原子 manifest。代码中不得出现 click、press/back、swipe、input、intent 或其他 UI 修改 API,
不得自动进入或退出确认页,也不得从前序项目、旧 XML 或推理写生产判据。