Files
cmroubao/docs/tasks/T-102.md
T

127 lines
6.3 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.
---
id: T-102
title: 浏览并采集最多 5 个候选
phase: 1
deps:
- T-101
status: DONE
created: 2026-07-25
context_ref: f226d0f
work_branch: main
write_paths:
- android-buyer/app/src/main/java/com/roubao/autopilot/MainActivity.kt
- android-buyer/app/src/main/java/com/roubao/autopilot/accessibility/**
- android-buyer/app/src/main/java/com/roubao/autopilot/pinduoduo/**
- android-buyer/app/src/main/java/com/roubao/autopilot/ui/screens/SearchProbeScreen.kt
- android-buyer/app/src/main/java/com/roubao/autopilot/workflow/WorkflowModels.kt
- android-buyer/app/src/main/res/xml/buyer_accessibility_service.xml
- android-buyer/app/src/test/java/com/roubao/autopilot/pinduoduo/**
- docs/00-ai-start-here.md
- docs/02-requirements.md
- docs/03-tech-stack.md
- docs/04-architecture.md
- docs/05-coding-rules.md
- docs/current-state.md
- docs/tasks/T-102.md
- progress.md
---
## 问题 / 背景
T-101 已能稳定进入固定词结果页,但尚未证明可以识别独立商品卡、进入详情、保存证据
并返回同一结果页。T-102 只验证有界候选浏览,不进行匹配判断、下单或支付。
## 关联需求与交互
- 功能:F-005 的最多 5 个候选采集部分、F-007 安全失败。
- 用户故事:US-004、US-006。
- 交互:Android“探针”页展示候选计数和当前步骤。
- 架构:`WorkflowRunner` + `PinduoduoCandidateAutomation` + 无障碍 driver +
App 内部缓存证据。
## 方案
1. 只从已确认的搜索结果页识别主 RecyclerView 的直属商品卡。
2. 商品卡必须可见、启用、可点击,包含图片和有限文本;用文本 SHA-256 去重,不在
日志或 UI 展示标题。
3. 每次只打开一个候选;详情页必须由稳定语义组合确认,保存全屏 PNG、文本指纹和
节点计数后立即返回结果页。
4. 最多采集 5 个不同候选,最多滚动结果列表 2 次;没有无界循环或翻页。
5. 登录、验证码、风控、未知页、订单和支付边界立即阻塞;绝不点击详情页购买控件。
## 验收要点
- [x] 从 T-101 结果页依次进入候选详情并返回。
- [x] 采集数量始终不超过 5,结果滚动次数始终不超过 2。
- [x] 每个候选有内部缓存 PNG、SHA-256、尺寸和语义节点证据。
- [x] 证据文件名匿名,普通日志和 UI 不输出商品标题。
- [x] 全流程不使用坐标,不点击购买、订单或支付控件。
- [x] 页面未知或安全边界出现时产生可区分的 `BLOCKED`。
- [x] Fake driver 自动化测试覆盖成功、去重、上限和安全停止。
- [x] 拼多多 8.17.0 真机 smoke 采集 5 个候选并返回结果页。
- [x] `lintDebug test assembleDebug` 通过,默认 APK 不含私有 fixture。
## 边界
- 不评估候选是否匹配;T-104 才接入候选评估。
- 不把候选证据上传网络;T-202 以后再接后端证据接口。
- 不点击购买、拼单、加入购物车、订单或支付相关节点。
- 不保存真实蝦皮输入或把商品详情文本写入普通日志。
## 执行记录
### 2026-07-25:任务开始
- 基于 T-101 提交 `f226d0f` 开始。
- 脱敏结构审计确认拼多多 8.17.0 结果页主 RecyclerView 和双列商品卡;详情页有
可点击返回语义以及联系客服、收藏、店铺语义,当前未出现订单或支付边界。
### 2026-07-25:实现
- 新增 `PinduoduoCandidateAutomation` 和复合探针 workflow。一次 session 最多尝试
5 个不同卡片、最多发出 2 次结果滚动;预算在动作前消耗,runner retry 不会重置。
- 主结果 RecyclerView 必须可滚动、覆盖至少 90% 宽度且拥有足够节点。候选卡必须
至少 80% 可见、宽度在单列范围、含图片/价格/至少 2 个语义文本;根不可点击时
只接受唯一覆盖卡片至少 85% 面积的点击目标,小型嵌套按钮不会被选中。
- 详情页同时要求可点击返回、联系客服/收藏/店铺至少两类语义、宽 ViewPager 和宽
可滚动主列表。详情页动作白名单只有截图和一次全局返回,返回后必须重新确认固定
查询结果页。
- Android 11/API 30+ 使用声明了 `canTakeScreenshot` 的无障碍截图 API。Hardware
buffer 在独立执行器转换和压缩并始终关闭;8 秒超时后结构化失败,不绕过安全窗口。
- 每个候选只保存匿名 PNG、卡片/详情语义 SHA-256、节点计数、文件 SHA-256、字节数
和尺寸到 App cache;manifest 不保存标题或页面原文,文件写入在 IO dispatcher。
- 探针页增加候选 `0/5` 计数和第五步;仅记录 workflow/候选阶段枚举与截图错误码。
### 2026-07-25:自动化验证
- `gradlew.bat lintDebug test assembleDebug --no-daemon` 成功。
- App Debug/Release、task contract 和导入器共 14 份报告、78 次测试,0 failure、
0 error、0 skipped。
- Fake driver 覆盖 5 个去重候选、候选硬上限、旧页面有界过渡、两次滚动上限、
空列表、安全阻塞、截图失败以及从已验证详情页安全恢复。
- 普通 Debug APK 中 `assets/probe-fixtures/` 条目数为 0。
### 2026-07-25:真机 smoke
- OnePlus PKG110、Android 16/API 36、拼多多 8.17.0 上,从肉包按钮启动后 20 秒内
依次采集 5 个候选并返回固定词结果页;肉包显示 `5 / 5` 和五步完成。
- cache manifest 为 5 条,匿名文件名合法;5 个 PNG 均为 `1080x2376`,字节数为
正数,文件 SHA-256 与 manifest 全部一致。
- 最终结果页订单/支付边界计数为 0;logcat 没有肉包崩溃或 ANR,阶段日志不含商品
标题或页面原文。
- 真机审计 XML/PNG 位于被忽略的 `.local/`,候选证据位于 App 内部 cache,均未纳入
Git。
### 2026-07-25:修正记录
- 首次运行在候选点击后把短暂保留的旧结果页误判为未知。改为只在固定 20 次观测
预算内等待结果页和详情页过渡;任何安全阻塞仍立即停止。
- 调试期间旧 Activity 造成终态读取混淆;最终 smoke 先清理肉包任务栈,再用
`FLAG_ACTIVITY_REORDER_TO_FRONT` 返回原实例核验,未创建第二个 workflow。
## 后续
- T-103 使用 T-004 的私有 ProbeTask 接入结构化需求提取;不能把订单号或店铺名发给
模型。
- T-104 才把候选截图交给评估适配器;T-102 不声明任何候选匹配结论。