docs: import wiki at afc651f75a3a
+129
@@ -0,0 +1,129 @@
|
||||
<!-- docs-wiki-sync:docs/tasks/T-102.md@afc651f75a3abc2676bb13aa8a80f6aa6a25a72e -->
|
||||
> 同步来源:[`docs/tasks/T-102.md`](/chengma/mroubao/src/commit/afc651f75a3abc2676bb13aa8a80f6aa6a25a72e/docs/tasks/T-102.md) · commit `afc651f75a3a`
|
||||
|
||||
---
|
||||
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 不声明任何候选匹配结论。
|
||||
Reference in New Issue
Block a user