From cb91aacb8e1218184dadd3bd6da395c0fdcb06c1 Mon Sep 17 00:00:00 2001 From: ila Date: Fri, 7 Aug 2026 16:36:56 +0800 Subject: [PATCH] docs: import wiki at afc651f75a3a --- T-247.-.md | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 T-247.-.md diff --git a/T-247.-.md b/T-247.-.md new file mode 100644 index 0000000..5445c04 --- /dev/null +++ b/T-247.-.md @@ -0,0 +1,141 @@ + +> 同步来源:[`docs/tasks/T-247.md`](/chengma/mroubao/src/commit/afc651f75a3abc2676bb13aa8a80f6aa6a25a72e/docs/tasks/T-247.md) · commit `afc651f75a3a` + +--- +id: T-247 +title: 修复图片搜索循环并完成两个 SKU 候选回传 +phase: 2 +deps: + - T-211 + - T-213 + - T-246 +status: DONE +created: 2026-07-30 +context_ref: e38ff08 +work_branch: null +write_paths: + - docs/tasks/T-247.md + - docs/current-state.md + - android-buyer/app/src/main/** + - android-buyer/app/src/test/** +--- + +## Bug / 背景 + +Admin 分派真实采购任务后,Roubao 会每约 10 秒重新开始一次拼多多图片搜索。部分轮次只 +进入摄像头扫描页,没有选择已经写入系统相册的参考图;部分轮次回到拼多多主页后重新 +搜索。连续十余轮仍没有候选回传,后台任务保持 `RUNNING`。 + +2026-07-30 真机日志确认: + +1. Roubao 在 `08:46:19`、`08:46:29`、`08:46:39`、`08:46:49` 分别创建新的 + `Pictures/RoubaoSearch/roubao-search-*.jpg`,周期与 App 的 10 秒自动轮询一致。 +2. 每张临时图片约 1 秒后被删除;同一时间拼多多摄像头被打开。 +3. 每轮 `openApp()` 使用 `FLAG_ACTIVITY_CLEAR_TASK` 重启拼多多 Activity 栈,导致当前 + 摄像头页、结果页或详情页被丢弃并回到主页。 +4. 单轮工作流失败后只清空进程内 Job;后台 execution 仍为 `RUNNING`,自动调度下一轮 + 没有任务级累计次数、熔断状态或稳定失败事件。 +5. 图片搜索页和相册网格已有真机 UI 基线,但页面切换期间的短暂未知状态会过早结束 + 单轮流程。 +6. 候选详情当前只读取首屏语义和首屏 OCR,没有按既定方案滚动到商品详情/参数区域读取 + `goods_id`;缺少 ID 的真实商品被静默丢弃。 +7. 规格选择返回部分证据时仍可能保存候选,没有在保存前再次证明目标颜色和尺码均已 + 唯一选中。 + +## 修订契约 + +### 自动尝试与熔断 + +- 自动图片搜索按 execution 持久化尝试状态,进程重启后继续同一计数。 +- 首版最多自动尝试 2 次;成功回传候选、execution 改变或任务终止时停止继续搜索。 +- 两次均失败后进入本地熔断,不再启动拼多多;记录步骤、稳定失败码和尝试次数,并通过 + 既有 execution event outbox 回传后台。 +- 人工故障重试必须是显式动作;不能由 10 秒 heartbeat/claim 轮询隐式清除熔断。 + +### 图片搜索交接 + +- 拼多多已在前台时复用当前 Activity;从 Roubao 首次打开时只使用 + `NEW_TASK | SINGLE_TOP`,不得清空拼多多任务栈。 +- 为主页到摄像头/相册页、相册到结果页提供受工作流总 timeout 约束的稳定等待窗口; + 短暂 `UNKNOWN` 只能等待,不能立即重新启动整轮。 +- 只在确认当前页为图片搜索页、准备图仍是系统相册最新 JPEG 且找到唯一“最近项目” + 网格后点击第一张图片。 +- 同一轮复用同一个 MediaStore URI;只在确认结果、明确失败或停止后清理。不得在拼多多 + 仍可能异步读取时创建下一张参考图。 + +### 商品身份、SKU 与两个候选 + +- 本次闭环固定收集 2 个候选;单轮最多扫描 120 个不同商品、滚动结果页 30 次, + 候选步骤最长 10 分钟,不凑数。 +- 规格面板只在目标颜色、尺码均唯一、可用且动作后 + 复读为已选择时,才允许保存 SPECIFICATION 证据。 +- 规格验证完成后才保存 DETAIL 截图并解析商品身份;先在商品详情页有界向下滚动, + 逐屏读取无障碍语义,必要时使用本地 + ML Kit OCR;只接受唯一、带 `goods_id/商品编号/商品 ID` 语义的纯数字 ID。 +- 拼多多 8.17 详情页不暴露 ID 时,允许打开原生分享面板、点击“复制链接”,并在 App + 内解析唯一 HTTPS 链接。只允许 `p.pinduoduo.com` 和 `mobile.yangkeduo.com`, + 最多 3 次跳转、单次 6 秒、正文 64 KiB;不携带 Cookie,不记录原始链接。解析到 + 唯一 ID 后生成规范 URL `https://mobile.yangkeduo.com/goods.html?goods_id=`。 +- 两个候选均须包含规范链接、标题、已验证 SKU、组合价格、DETAIL/SPECIFICATION 本地 + 图片证据、采集指纹和时间,并通过既有候选批次接口保存到 Admin。 +- 候选批次成功后后台进入待采购员确认阶段,Roubao 不再搜索。 + +## 方案 + +1. 增加 execution-scoped 搜索尝试 gate,使用小型持久化状态记录 execution ID、已开始 + 次数和最终失败;将 gate 判断放在自动调度器启动 Job 之前。 +2. 移除图片搜索 driver 的 `CLEAR_TASK`,前台已是拼多多时不重复启动 launcher;放宽 + 页面切换的稳定等待,但保持每步 timeout 和未知页 fail-closed。 +3. 将候选目标设为 2,并把候选扫描预算与成功候选数分离,允许跳过不匹配 SKU 或缺少 + `goods_id` 的商品。 +4. 新增详情页受控滚动和身份解析;规格关闭后再扫描 ID,因此无需为了打开规格返回顶部。 +5. 新增严格的最终 SKU 匹配策略;不满足颜色和尺码两个硬约束时关闭面板并返回结果页, + 不写候选证据。 +6. 在失败/熔断和成功回传处增加结构化日志及 execution event;Admin 候选数据继续使用 + 现有 API、数据库与鉴权图片路由,不新增 PDD 服务端抓取。 +7. MainActivity 使用 `singleTask`,每轮写入前清理肉包专属相册目录的崩溃遗留临时图; + 320×320 ERP 图只在临时搜索副本中等比例放大,原始任务图和哈希证据不变。 +8. 自动后台任务默认 `MANUAL_FIRST`;旧 `AI_ASSISTED` execution 中,VLM 提取与图片 + 搜索并行,VLM 失败或软警告不能阻断可由原始 ERP SKU 唯一解析的硬匹配。 + +## 验收要点 + +- [x] Roubao 被 force-stop 后进程不存在且不再创建参考图或拉起拼多多。 +- [x] 同一 execution 自动图片搜索最多启动 2 轮,进程重启不能重置次数。 +- [x] 拼多多已在摄像头、图片结果或详情页时不因 launcher 清栈回主页。 +- [x] 真机自动选择任务参考图并进入“搜图片同款”结果页,不误用摄像头拍照内容。 +- [x] 不匹配目标颜色或尺码的商品不会保存为候选。 +- [ ] 详情滚动只接受唯一 `goods_id`,生成的规范 URL 与 ID 一致。 +- [ ] 恰好 2 个真实 SKU 匹配候选回传后台;Admin 可查看标题、链接、SKU、价格及两张 + 本地图片证据。 +- [ ] 候选回传后任务进入后台确认阶段,手机停止搜索并等待 Admin 选择。 +- [x] 失败达到上限后手机停止外部动作,并排队回传步骤、失败原因和尝试次数。 +- [x] Android 单测、Debug/Release 构建通过,真机 smoke 不触发下单或支付。 + +## 边界 + +- 本任务先证明 2 个候选闭环,不宣称 Top 5 已完成真实验收。 +- 不自动付款,不点击最终提交订单,不改变 T-218 submission fence。 +- 不保存或读取拼多多 Cookie、Token;分享短链只在 App 内按域名、跳转、超时和正文上限 + 解析,不由后端请求拼多多商品页。 +- 页面、SKU、商品 ID、价格或证据任一不确定时跳过或熔断,不通过增加无限重试提高成功率。 +- 真机 smoke 到 Admin 出现两个候选即停止;采购员确认后的下单链路另行复核。 + +## 执行记录 + +- 2026-07-30:通过 ADB 强制停止 `com.roubao.autopilot`,确认进程不存在;拼多多留在主页。 +- 2026-07-30:读取真机 logcat、SQLite execution/candidate 状态和 T-246 代码,确认本次 + 循环由 10 秒调度、整轮无熔断和 launcher 清栈共同造成,不是 Admin 分派、参考图下载、 + VLM 网络或后台候选接口失败。 +- 2026-07-30:实现 execution-scoped 两轮持久化 gate、单任务 Activity、图片搜索状态 + 恢复、临时图清理/放大、ERP SKU `草莓 + M` 提取、严格规格选择、两个候选批次、 + 分享链接受限解析和 execution event。 +- 2026-07-30:PKG110 / Android 16 / 拼多多 8.17 真机确认自动选择参考图并进入 + “搜图片同款”;连续多轮只执行每 execution 两次。真实规格日志自动选中过 + `短袖草莓套装 M 建议70-90斤` 和 `短七字母草莓套装 M 建议70-90斤`,不匹配项均关闭 + 规格后返回结果页;全程未进入下单或支付。 +- 2026-07-30:真机确认拼多多 8.17 分享面板稳定暴露“复制链接”,并据此增加受限分享 + 解析路径;最后一次真实搜索未同时得到两个可保存候选,因此 Admin 两候选批次、规范 + URL 和等待确认阶段仍未完成端到端验收。系统返回 `TARGET_NOT_READY` 并停止,没有凑数。 +- 2026-07-30:`./gradlew.bat :app:testDebugUnitTest :app:assembleDebug + :app:assembleRelease` 通过;Debug APK 已覆盖安装到 PKG110。