docs: import wiki at afc651f75a3a
+156
@@ -0,0 +1,156 @@
|
|||||||
|
<!-- docs-wiki-sync:docs/tasks/T-252.md@afc651f75a3abc2676bb13aa8a80f6aa6a25a72e -->
|
||||||
|
> 同步来源:[`docs/tasks/T-252.md`](/chengma/mroubao/src/commit/afc651f75a3abc2676bb13aa8a80f6aa6a25a72e/docs/tasks/T-252.md) · commit `afc651f75a3a`
|
||||||
|
|
||||||
|
---
|
||||||
|
id: T-252
|
||||||
|
title: 修复 Android 16 商品链接读取并回传身份未解析候选
|
||||||
|
phase: 2
|
||||||
|
deps:
|
||||||
|
- T-246
|
||||||
|
- T-251
|
||||||
|
status: DONE
|
||||||
|
created: 2026-07-30
|
||||||
|
context_ref: 920886c
|
||||||
|
work_branch: null
|
||||||
|
write_paths:
|
||||||
|
- docs/tasks/T-252.md
|
||||||
|
- docs/current-state.md
|
||||||
|
- android-buyer/app/src/main/**
|
||||||
|
- android-buyer/app/src/test/**
|
||||||
|
- android-buyer/app/src/androidTest/**
|
||||||
|
- android-buyer/app/build.gradle.kts
|
||||||
|
---
|
||||||
|
|
||||||
|
## 问题 / 背景
|
||||||
|
|
||||||
|
任务 `09240616-5d87-4ab1-a37a-57949725f8b2` 最终以
|
||||||
|
`CANDIDATE_IDENTITY_UNRESOLVED` 失败。人工在同一张参考图的拼多多结果中可以找到
|
||||||
|
符合黑色 L 码的商品,但 Admin 没有候选。
|
||||||
|
|
||||||
|
真机 Android 16/ColorOS 系统日志证明:拼多多在详情页成功写入“复制链接”后,
|
||||||
|
系统拒绝后台 Roubao 读取剪贴板,理由为应用不在前台。当前候选流程只有取得唯一
|
||||||
|
`goods_id` 和规范 PDD URL 后才保存证据,因此已经打开详情、核验规格的商品也被直接
|
||||||
|
丢弃,Admin 无法看到标题、规格、价格、图片或失败阶段。重复执行三轮图片搜索不能
|
||||||
|
改变系统剪贴板权限,只增加时间成本。
|
||||||
|
|
||||||
|
本任务修复商品身份主链路,并保留 fail-closed 边界:只有身份完整的候选可进入 Admin
|
||||||
|
选择和后续下单;身份未解析的匹配商品只作为不可下单观察回传。
|
||||||
|
|
||||||
|
## 现场证据
|
||||||
|
|
||||||
|
- PDD 8.17 详情页“分享”以唯一可点击语义暴露,分享面板“复制链接”也可唯一定位,
|
||||||
|
因此不是按钮文案或控件改版。
|
||||||
|
- 系统日志先记录拼多多前台写剪贴板成功,约三秒后记录
|
||||||
|
`Denying clipboard access to com.roubao.autopilot, application is not in focus`。
|
||||||
|
- 当前 Activity/Window 和详情页无障碍文本不暴露 `goods_id`;页面 OCR 也没有权威
|
||||||
|
商品编号,不能用 VLM 或视觉猜测替代。
|
||||||
|
- 本地 attempt gate 为三轮、`terminal_queued=true`,候选证据缓存为空,说明候选在
|
||||||
|
Android 保存/回传前被拒绝;后端没有丢失已上传数据。
|
||||||
|
- 后端候选契约允许 `goods_id/product_url` 同时为空并只保存 observation;创建下单
|
||||||
|
授权时会拒绝没有 `candidate_platform_products` 的候选,可复用该安全边界。
|
||||||
|
|
||||||
|
## 关联需求与交互
|
||||||
|
|
||||||
|
- 功能:F-004、F-005、F-006、F-007
|
||||||
|
- 用户故事:US-003、US-004、US-006
|
||||||
|
- Android:图片搜索、规格硬匹配、候选证据、自动轮次和终态 outbox
|
||||||
|
- Admin:沿用候选观察展示;身份未解析项显示为空链接且任务最终为 `FAILED`
|
||||||
|
- 架构/API:复用现有候选批次允许空平台身份的契约,不新增后端迁移或第三方代理
|
||||||
|
|
||||||
|
## 行为契约
|
||||||
|
|
||||||
|
### 前台剪贴板中继
|
||||||
|
|
||||||
|
- 拼多多点击“复制链接”成功后,Roubao 启动内部、`exported=false`、不进入最近任务的
|
||||||
|
透明中继 Activity;只有该 Activity 获得窗口焦点后才能读取剪贴板。
|
||||||
|
- 中继请求必须绑定一次性 request ID 和本次复制开始时间,最长等待 3 秒;剪贴板必须
|
||||||
|
是复制开始后写入、只有一项、长度不超过 2048,并且恰好包含一个允许的 HTTPS PDD
|
||||||
|
URL。
|
||||||
|
- 中继只在内存中返回文本,不写日志、不持久化、不上传原始分享文案;完成、超时或取消
|
||||||
|
后立即关闭并回到原拼多多详情页。
|
||||||
|
- 中继启动失败、没有获得焦点或焦点后仍不能读取时返回稳定的剪贴板身份失败,不回退到
|
||||||
|
后台直接读取。
|
||||||
|
|
||||||
|
### 身份解析结果
|
||||||
|
|
||||||
|
- 商品身份解析返回显式结果,而不是以空 capture 混合所有失败:
|
||||||
|
`SHARE_ACTION_UNAVAILABLE`、`COPY_LINK_UNAVAILABLE`、
|
||||||
|
`CLIPBOARD_RELAY_UNAVAILABLE`、`CLIPBOARD_ACCESS_DENIED`、
|
||||||
|
`SHARED_LINK_FORMAT_INVALID`、`SHARED_LINK_NETWORK_FAILED`、
|
||||||
|
`IDENTITY_CONFLICT`。
|
||||||
|
- 详情文本和最多两个视口 OCR 仍优先;只有两者没有唯一结果时才使用分享链接。
|
||||||
|
- 短链仍只允许 `p.pinduoduo.com` 和 `mobile.yangkeduo.com`,最多三次受控重定向、
|
||||||
|
6 秒总网络预算和 64 KiB 响应,不放宽 SSRF 边界。
|
||||||
|
- VLM 不得生成或猜测 `goods_id`。
|
||||||
|
|
||||||
|
### 身份未解析观察
|
||||||
|
|
||||||
|
- 规格硬匹配已经通过但身份解析失败时,保存标题、规格摘要、价格、card/detail 指纹、
|
||||||
|
详情截图、规格截图、搜索轮次/排名和身份失败码;`goods_id/product_url` 同时为空。
|
||||||
|
- 每个 execution 最多保留两个身份未解析观察,跨轮持久保存;它们不计入“两个可采购
|
||||||
|
候选”目标,不触发搜索成功,也不占用 resolved goods ID 去重。
|
||||||
|
- 身份完整候选继续按原逻辑增量回传。若最终失败,App 必须在 `FAIL` 终态前上传
|
||||||
|
“已解析候选前缀 + 最多两个未解析观察”的 partial candidate snapshot;未解析项使用
|
||||||
|
无 match metadata 的诊断观察形式,批次最多五项。
|
||||||
|
- 任务最终保持 `FAILED`,Admin 可查看观察和证据但不能选择或创建下单授权。若搜索最终
|
||||||
|
成功,完成批次只包含身份完整候选,不把诊断项混入可选集合。
|
||||||
|
|
||||||
|
### 重试与终态
|
||||||
|
|
||||||
|
- `CLIPBOARD_RELAY_UNAVAILABLE` 和 `CLIPBOARD_ACCESS_DENIED` 是设备级系统故障;
|
||||||
|
首轮确认后立即写 `CANDIDATE_IDENTITY_INFRASTRUCTURE_FAILED` 终态,不重复三轮图片
|
||||||
|
搜索。
|
||||||
|
- 分享按钮缺失、复制按钮缺失、短链格式/网络失败或单个商品身份冲突仍可在当前轮继续
|
||||||
|
检查其他商品,并受 T-250/T-251 原有轮次和时间预算限制。
|
||||||
|
- 终态顺序固定为 evidence、partial candidates、失败事件、`FAIL`;上传成功后停止
|
||||||
|
execution heartbeat。任何路径都不得进入购物车、订单提交或支付。
|
||||||
|
|
||||||
|
## 方案
|
||||||
|
|
||||||
|
1. 新增透明 `PinduoduoClipboardRelayActivity` 和进程内 broker,以窗口焦点、时间戳、
|
||||||
|
单项剪贴板和 PDD URL allowlist 验证复制结果。
|
||||||
|
2. 将候选 driver 的身份解析改为 sealed result,并让短链 resolver 区分格式、网络和
|
||||||
|
无法解析;workflow 将原因映射为稳定失败码。
|
||||||
|
3. 扩展候选证据和 progress store 支持空平台身份及身份失败码,resolved/diagnostic
|
||||||
|
分开计数、去重和排序;终态前才附加 diagnostic observation。
|
||||||
|
4. 扩展 terminal policy,使确定性的剪贴板基础设施故障可以在未耗尽三轮时关闭 gate
|
||||||
|
并排队终态。
|
||||||
|
5. 增加纯 Kotlin 单测、Android 构建验证,并在 PKG110 上验证复制、前台读取、短链
|
||||||
|
解析、返回详情页和 Admin 候选结果。
|
||||||
|
|
||||||
|
## 验收要点
|
||||||
|
|
||||||
|
- [x] Android 16/ColorOS 上前台中继可读取新复制的 PDD 白名单链接,不再使用后台
|
||||||
|
accessibility service 读取剪贴板。
|
||||||
|
- [x] 中继读取结果交给受限短链解析器生成唯一 `goods_id` 和规范商品 URL,完成后
|
||||||
|
自动关闭并恢复前一个 Activity。
|
||||||
|
- [x] 两个身份完整候选仍按 resolved 数量增量回传并进入 Admin 等待确认。
|
||||||
|
- [x] 身份失败时最多保留两个不可下单观察及其标题、SKU、价格和两张证据图,并在
|
||||||
|
终态前作为无采集元数据的 partial snapshot 回传。
|
||||||
|
- [x] 未解析观察不计入成功数量,空平台身份沿用后端禁止创建下单授权的边界。
|
||||||
|
- [x] 确定性剪贴板基础设施故障首轮进入终态,不重复三轮图片搜索。
|
||||||
|
- [x] 原始剪贴板文本不落盘、不入日志、不上传。
|
||||||
|
- [x] Android 单测、lint、Debug/Release 构建、API 36 真机测试和根 `init.ps1`
|
||||||
|
通过。
|
||||||
|
|
||||||
|
## 边界
|
||||||
|
|
||||||
|
- 不让后台、VLM 或 Admin 猜测商品 ID,不以标题/图片相似度替代平台身份。
|
||||||
|
- 不放宽 PDD host、URL、重定向、响应大小和商品 ID 格式限制。
|
||||||
|
- 不自动接受身份未解析观察,不创建授权命令,不进入下单或支付。
|
||||||
|
- 不改变 T-249 的重试安全边界和 T-251 的三轮耗尽终态。
|
||||||
|
|
||||||
|
## 执行记录
|
||||||
|
|
||||||
|
- 2026-07-30:完成真机只读诊断;打开当前结果第一项、确认“分享/复制链接”语义并
|
||||||
|
手工复制一次后恢复图片搜索结果页,未选择 SKU、加入购物车、提交订单或支付。
|
||||||
|
- 2026-07-30:新增 `exported=false` 透明前台中继和一次性 broker;用剪贴板时间戳、
|
||||||
|
单项、2048 字符和 PDD HTTPS allowlist 拒绝陈旧或外部内容,删除 accessibility
|
||||||
|
service 的后台剪贴板入口。
|
||||||
|
- 2026-07-30:身份解析改为七类显式结果;候选进度 schema v2 将 resolved 与最多
|
||||||
|
两个 diagnostic 分开计数、去重和持久化,终态前把 resolved 前缀和 diagnostic
|
||||||
|
统一转为不可推荐的无采集元数据快照,再排队失败事件和 `FAIL`。
|
||||||
|
- 2026-07-30:Android 单测 232 项通过,lint、Debug/Release 构建通过;PKG110
|
||||||
|
Android 16/API 36 仪器测试 `1/1` 通过,证明焦点 Activity 能读取新写入 PDD URL
|
||||||
|
并返回前一 Activity。安装 `1.4.17 (22)` 后已复核采购无障碍、悬浮窗、通知和
|
||||||
|
Shizuku 授权处于启用状态;未进入购物车、提交或支付。
|
||||||
Reference in New Issue
Block a user