Files
cmbuyer/docs/current-state.md
T

234 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 当前实现状态
> 本文是可覆盖的**项目级快照**,记录代码与任务的现实状态。
> 执行记录写进各任务文件(`docs/tasks/T-<编号>.md`)的 `## 执行记录`,不在本文重复维护。
## 职责边界
- [`tasks/`](tasks/README.md):任务规格、依赖、状态(frontmatter)和执行记录,一任务一文件。
- [`06-tasks.md`](06-tasks.md):只读路线图,维护阶段划分、里程碑和待办池。
- `current-state.md`:当前快照,可覆盖更新。
## 当前快照
- 日期:2026-08-05
- 阶段:**Phase 1 · T-103 规格选择/读价与 Phase 2 安全服务端任务并行**
- MVP 形态:手工填链接建单 → 批量“开始采购”并签发一次性授权 → 定时领取 → 同一趟精确
选规格 / 三道价格闸门 / 提交围栏 / 点击一次 → 待付款。管理员点击“开始采购”即授权桌面端
创建待付款订单;不再有试选后确认,系统绝不自动付款。
- 技术栈:已定。采购服务(`admin/`)使用 Go 1.23+ / gin / SQLite;采购工具(`client/`)
使用 Python 3.11+ / uiautomator2 / PySide6。
详见 [`03-tech-stack.md`](03-tech-stack.md)
- 生产代码:`admin/` 已有登录/会话、手工 DRAFT 建单、批量开始采购与一次性授权、任务详情、内部
原始截图、设备身份,以及已授权任务的原子领取/幂等重放/租约续期;
`client/` 已有 Python 包、PySide6 最小入口、运行目录与日志脱敏策略,以及显式 serial 的 ADB
连接边界、本地基线取证 CLI、受限商品链接打开取证 CLI、人工声明规格面板状态的只读取证 CLI,
绑定 PKG110 / Android 16 / 拼多多 8.17.0 的证据工具,以及受控规格入口、精确规格选择、SKU 当前价
读取、原始截图和一次安全退出能力;并已具备严格 localhost claim/renew/evidence HTTP、Windows DPAPI
凭据保护、SQLite append-only 恢复状态图、Global named mutex 与 durable gateway。原生桌面主界面、
显式本地配置、停止/重启会话边界和安全轮询协调器已实现;未注入单趟执行 consumer 时保持零领取。
独立的一次性尺码 reveal 取证脚本已就绪,但尚未成为生产 Flow;真机能力与桌面界面仍待最终人工
验收,数量/确认页/提交仍未开放。
- 测试:采购服务已覆盖登录、建单、授权、详情/证据、设备身份、迁移、原子 claim/renew 与竞态;
采购工具 255 项离线单元测试(全部 mock,不连接真机)。
- 数据:受保护迁移已落到 `00005_task_claims.sql`。旧两趟模型已移除;开始采购会锁定任务快照并签发
一次性授权,领取会创建唯一 attempt/claim、HMAC claim token 与有界租约。T-211 已统一 title、SKU、
goods_id 与金额的双端 wire 上限,并证明最坏合法 claim 响应小于 32 KiB。仓库不含业务实例数据。
- 标准启动路径:Windows PowerShell 运行 `./init.ps1`,Unix shell 运行 `./init.sh`。Windows 入口
优先使用合规的既有 venv;仅在其缺失时才从 Python Launcher 已安装版本中选择最高的 Python 3.11+,
并且不覆盖低版本环境;成功后打印真实启动命令。
- 标准验证路径:`./init.ps1` 已实际跑通 admin 的 mod download / test / vet / build、client 的
editable install / 包导入 / unittest / compileall,以及仓库上下文校验。可单独运行两端命令诊断。
- 当前设备门禁:人工已确认拼多多 8.17.0、goods_id `937122477375` 的衣服商品只能通过“快要抢光”
打开规格面板;T-110 已获项目所有者批准,只把该证据/版本绑定的精确唯一入口作为受控导航。
T-103 的隔离 capability 仍不得包含数量、确认页、提交订单、付款或通用点击;这些动作由后续任务
分别取证后才接入生产单趟流程。T-103 旧 v5 派生 XML 中的“打开即目标预选”已被 2026-08-05
五组最新 live 证据纠正:真实初态为颜色与尺码均未选,目标颜色选中后尺码仍未选且不在视口;
S 非目标值与恢复目标 M 的前后态已由人确认。底部“提交订单 ¥12.88”继续属于硬拒绝区。项目已停止
遮罩器开发,T-204 已允许认证设备上传内部原始截图供管理员查看。入口父链证据已由人确认并
最新失败证据已纠正入口绑定:此前实现误点商品内容区同名促销小字;真实入口是底部购买区第一行
`快要抢光 + 金额` 的精确文本叶节点中心。第二行“免拼购买”只能作为不可点击的证据绑定兄弟节点
校验结构,绝不作为选择器或目标;按钮金额不作为价格来源。提交 `2f1380d` 已把入口改为只点击
第一行中心 `(865,2218)`,旧内容区小字为零点击反例并保留一次点击无重试。T-103 还缺一组窄动作
证据:颜色已选且尺码未选/隐藏时执行一次受控 reveal,动作后 M 仍未选但已可见。提交 `e8ca738`
已增加与生产 Flow 隔离的固定一次 reveal 证据脚本:只在完整前置与安全通道两次重证后发送一次,
RPC 结果不明只读调和且不重试,成功不 Back 并等待人工核对;在该证据获人确认前仍不把 reveal
接入生产 Flow。之后才进行入口、颜色、reveal、目标 M、读取 `12.88` 和一次 Back 的最终人工真机验收。
完整事件链必须等待 T-107 与 T-210:先让 Gate2/Gate3 证据进入真实 schema,再实现 T-205 事件,
不用 mock 或无证据成功事件抢跑。
## 当前目录要点
| 路径 | 状态 | 说明 |
| --- | --- | --- |
| `docs/` | 已有 | 项目规范化文档,本次已完整生成 |
| `docs/tasks/` | 已有(含 T-001~T-111、T-201~T-211、T-301~T-308、T-400~T-405) | T-303、T-211 已完成;T-304 代码完成后保持 DOING 等人工 UI 复核;T-103 等最终真机验收;双端围栏、真实提交、调和、打包与只读验收均已落成任务 |
| `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 恢复底座及受控规格选择/读价/安全退出;数量、确认页和提交未开放 |
| `init.ps1` / `init.sh` | 已完成 | 统一安装与离线验证入口;PowerShell 优先复用合规 venv,缺失时自动选择最高的 Python 3.11+,Unix 缺工具链明确失败 |
## 任务状态
任务状态以 `docs/tasks/` 各任务文件 frontmatter 的 `status` 为准。本节只写项目级摘要:
- 已完成:T-005(采购服务交互原型)、T-006(采购工具交互原型)、T-007(产品名称与
源码目录契约)、T-008(Vikunja 任务权威与单向导出)、T-009(MVP 关键路径与并行波次),
以及 T-001(采购服务 Go 骨架)。
- 已完成:T-002(采购工具 Python 骨架)、T-003(双端统一初始化与验证入口)、
T-004(核心数据模型)、T-101(真机环境盘点与 USB/WiFi 双通道人工验收)、T-102(canonical
链接打开与目标商品/隐私人工验收)。
- 已完成 T-010(安全并行门禁)、T-201(管理员登录与会话)与 T-202(手工 DRAFT 建单和
基础列表)。T-202 已通过主 agent 独立审查、竞态测试与完整门禁并合入主线,仍只创建/展示
`DRAFT`,未实现授权、设备领取或采购执行。
- 已完成 T-110、T-111、T-203、T-204、T-301 与 T-302。服务端已能授权、认证设备、原子领取、
稳定重放和续租;claim token 不是提交许可,尚无事件、提交围栏或结果 API。
- T-103 四态 classifier、精确颜色/S→M 选择、滚动态读价与独立一次性 reveal 取证脚本已实现并通过
独立审计,仍为 `DOING` 等人工真机验收;T-104~T-107 按数量/确认页风险逐段开放。真机运行要求
同一物理手机只保留一个 ADB 通道;CLI 已增加不回显页面
正文的固定白名单失败阶段码;`sku_entry` 动态页面误判已按最新真机证据修复,覆盖点击中心的浮窗
会保持零点击,入口失败也已细分为前置、发现、点击和面板后置验证四个固定子阶段。服务端后续顺序已收紧为
T-210 → T-205 → T-206 → T-207 → T-208。
- T-303 已完成并通过三重审查;T-304 的轮询会话、配置页和固定双 Tab 主界面已通过两轮独立代码审计,
当前 255 项客户端测试与根门禁通过,继续保持 `DOING` 等原生 Windows DPI、主题、高对比度、
Narrator 和纯键盘人工验收。客户端后续按依赖推进 T-306/T-307/T-308,再与 T-305 汇合到
T-400 离线一次性提交安全编排。围栏后管理链为 T-403 → T-402;T-401 必须在新的真实单趟重新
通过三闸门,首次点击后固定进入 `UNKNOWN`/人工调和,T-405 打包后由 T-404 只读验收。
- T-211 已完成 claim wire 字段上限闭合:创建、授权、candidate、持久化快照、重放、HTTP 输出和
客户端解析使用同一合法域;单侧畸形历史数据失败闭合且不写 EMPTY,最坏合法响应严格小于 32 KiB。
- 已确认原型继续只作信息架构依据;原型假数据不调用真实接口、不驱动真机。真机结论改变
可读字段时必须先回修原型与交互清单。
## 当前可运行内容
Windows 统一安装、离线验证与启动命令提示已可运行:
```powershell
.\init.ps1
```
它会在成功后输出以下真实启动命令,而不自动启动或连接设备:
```text
采购服务:cd admin; go run ./cmd/server
采购工具:cd client; .\.venv\Scripts\python.exe -m cmbuyer_client
```
采购工具当前可运行的离线验证与 wheel 元数据检查:
```powershell
cd client
.\.venv\Scripts\python.exe -m unittest discover -s tests -t .
.\.venv\Scripts\python.exe -m compileall -q src tests scripts
$wheelDir = Join-Path $env:TEMP ('cmbuyer-client-wheel-' + [guid]::NewGuid())
New-Item -ItemType Directory -Path $wheelDir | Out-Null
.\.venv\Scripts\python.exe -m pip wheel --no-deps . --wheel-dir $wheelDir
.\.venv\Scripts\python.exe scripts/verify_wheel_metadata.py (Get-ChildItem $wheelDir -Filter '*.whl').FullName
```
采购工具规范安装与本地开发入口:
```powershell
# 在仓库根执行统一初始化;成功后再进入 client/
.\init.ps1
cd client
.\.venv\Scripts\python.exe -m cmbuyer_client
```
`client/requirements.txt` 是唯一依赖来源,`client/pyproject.toml` 动态读取它生成 wheel 的
`Requires-Dist`。Python 3.12 与 3.14 均已验证离线测试、编译与 wheel 元数据;完整运行时依赖安装
(`pip install -e .`)已通过。`init.ps1` 优先使用合规既有 venv,缺失时自动选择最高的 Python 3.11+;
本机 Python 3.12 与 3.14 均已验证,主工作区当前选择 Python 3.14。桌面 GUI 与真机流程未作为 T-003
验收执行。
T-101 的人工真机验收命令(先把手机切到不含收货地址、手机号、支付信息或其他无关隐私的安全页面;
必须从 `adb devices -l` 手工复制在线 serial,不能留空或自动选择):
```powershell
# 仓库根目录;USB 和 WiFi 分开执行,每次只保留一个通道在线
D:\Portable\adb\adb.exe devices -l
.\client\.venv\Scripts\python.exe client\scripts\capture_device_baseline.py --serial <USB_SERIAL> --output-dir "$env:LOCALAPPDATA\cmbuyer\artifacts\T-101\usb-baseline" --timeout 10 --adb D:\Portable\adb\adb.exe
# WiFi 必须由人先建立通道、断开 USB 后再手工粘贴在线 WiFi serial;脚本不自动 connect/reconnect
.\client\.venv\Scripts\python.exe client\scripts\capture_device_baseline.py --serial <WIFI_SERIAL> --output-dir "$env:LOCALAPPDATA\cmbuyer\artifacts\T-101\wifi-baseline" --timeout 10 --adb D:\Portable\adb\adb.exe
```
脚本只读取非敏感设备元数据、拼多多版本、截图和完整 XML;不会打开商品或写页面判据。它对同机双
通道、身份读取失败、offline、unauthorized、超时或 serial 不存在均 fail closed。成功目录的
`manifest.json` 只记录元数据、产物路径和 SHA-256,不记录 XML 页面正文或原始 serial。T-101 已由人
完成两次验收并确认原始证据不含敏感信息;`--timeout` 约束 ADB 命令、ADB socket 以及截图/节点树的
公开 JSON-RPC 调用,uiautomator2 初始化仍有上游固定启动上限。截图/XML 只保留在本地,执行记录只写
路径和 SHA-256,原始证据不得提交 Git。
T-102 的人工真机验收命令(只接受唯一 canonical 链接;USB 或 WiFi 每次只保留一个通道在线):
```powershell
# 仓库根目录;从输出中手工复制本次在线 serial
D:\Portable\adb\adb.exe devices -l
.\client\.venv\Scripts\python.exe client\scripts\capture_product_open.py --serial <SERIAL> --url "https://mobile.yangkeduo.com/goods.html?goods_id=<GOODS_ID>" --output-dir "$env:LOCALAPPDATA\cmbuyer\artifacts\T-102\product-open-<GOODS_ID>" --timeout 10 --adb D:\Portable\adb\adb.exe
```
脚本只允许 Android `VIEW` intent,并把 package 固定为 `com.xunmeng.pinduoduo`;intent 后会在
`--timeout` 的有限窗口内只读轮询前台 package,解决 App 异步切换造成的一次性误判,超时仍会停止。
它不点击、滑动、输入或判断商品页节点,也不打开规格、读取价格、进入下单或支付。运行拼多多版本必须精确为
`8.17.0`,否则在 intent 前停止。成功后由人本地查看截图/XML,确认页面确为该 `goods_id` 对应商品并
检查无地址、手机号、支付信息或其他无关隐私;只回报 manifest 路径及截图/XML SHA-256,原始证据
不得提交 Git。T-102 已由人确认 goods_id `958756616606` 的目标商品及截图/XML 隐私,并完成验收。
T-103 已确认当前衣服商品只能从精确文案“快要抢光”进入规格面板;T-110 只批准该证据/版本绑定入口,
不授权“免拼购买 / 单独购买 / 直接拼成”等其他文案。2026-08-05 五组 live 证据证明面板刚打开时两维
均未选,选择目标颜色后尺码仍未选且在视口外;S 与恢复 M 的 exact selected 切换已经人工确认。
初态与滚动态的价格文案、坐标和容器会整体变化,必须按完整 profile 判断,禁止跨 profile 拼装。
正式闸门一只在目标颜色和 M 均精确选中后,从已取证滚动态的只读价格角色读取 `12.88`;原价
`29.88`、详情页数字和底部提交按钮价均不得成为候选,冲突时返回 unreadable。
本轮不再运行或修改截图遮罩器。T-103 已从五组本机 live 证据提取不含个人信息的最小 fixture,
并在真机运行时只返回获准摘要;原始截图展示/上传由 T-204 处理,完整 XML 不上传。面板四态
classifier、颜色与 S→M 精确选择、滚动态价格判据和独立一次性 reveal 证据脚本已经落地;生产 Flow
中的受控 reveal 仍必须等待动作前后 M 均未选的真机证据和人工确认,最终完整链路也必须由人验收。
## 关键背景
本项目是 `cmroubao`(Go 后端 + Android AccessibilityService)与 `cmpdd`
(Python + uiautomator2)两个前序项目的合并重启。
- 取 `cmroubao` 的后端任务生命周期、设备侧 API 形状、下单授权状态机、ERP 对接、管理 Web。
- 取 `cmpdd` 的 uiautomator2 真机自动化、按维度精确选规格、订单确认页读取、付款闸门。
- 丢弃自研 Android APK 与 AccessibilityService 感知层。
**前序项目是设计依据,不是事实来源。** 其中的结论(尤其是拼多多页面判据)必须在本项目
用真机重新验证,且记录取证时的拼多多 App 版本。
## 已知风险(开工前须知)
1. **M2 是生死线**:真机能按链接打开商品、精确勾选颜色分类和尺码、**读到该 SKU 单价**
(T-103)。M2 前可以写不依赖页面字段的管理员会话、DRAFT 建单和服务端授权事务;不能写
依赖未取证选择器的生产执行代码。真机结论改变字段时先回修契约与原型。
2. **拼多多页面结构随版本变化**,已观察到详情页无独立规格入口、价格节点被拆分等情况。
3. **授权卡死**:前序项目出现过 `EXECUTING` 授权永不推进导致任务锁死。本项目在 T-207
实现围栏前超时 / 放弃,在 T-208 实现围栏后调和;围栏后不得释放或重试。
4. **规格面板读价尚未形成生产判据**:已人工观察当前价与原价,但 T-103 仍需把证据固化为
唯一、版本绑定且排除按钮价的读取规则;失败就转人工,不删价格闸门。
5. **MVP 已收窄**:只做手工填链接、批量开始采购和单趟创建待付款订单。Excel、ERP、图搜、
批量顺序编排 / 暂停接管、订单自动核对、AI 辅助全部推到 V2(见 `06-tasks.md` 的
T-501~T-508)。
6. **App 版本必须 fail closed**:运行时拼多多版本与本项目已取证版本不一致就停止领取,
不允许用旧判据继续跑。
## 开始编码前检查
1. 读 [`../AGENTS.md`](../AGENTS.md)。
2. 读 [`00-ai-start-here.md`](00-ai-start-here.md),特别是「本项目的四条特有纪律」。
3. 读 [`05-coding-rules.md`](05-coding-rules.md),特别是第 1 节红线。
4. 在 `docs/tasks/` 找 `status: TODO` 且依赖均 `DONE` 的任务文件;暂无时先按
[`06-tasks.md`](06-tasks.md) 落成任务文件。
5. 在独立分支 / worktree 把任务改为 `DOING` 后再改生产代码。
## 维护规则
实际代码状态变化时同步更新本文:新增或移动入口文件、初始化框架、新增可运行命令、
发现文档与代码不一致、阶段或 blocker 变化。
任务长期状态改在对应任务文件的 frontmatter;每轮执行记录、验证命令、阻塞点和关键决策
写进该任务文件的 `## 执行记录`。本文只保留当前快照,不保留完整历史。