Page:
T-252
Pages
00-ai-start-here
01-vision
02-requirements
03-tech-stack
04-architecture
05-coding-rules
06-tasks
07-user-stories
08-interaction-checklist
Design
Home
Integrations-shunyunbao-contract
PPT
T-001
T-002
T-003
T-004
T-101
T-102
T-103
T-104
T-201
T-202
T-203
T-204
T-205
T-206
T-207
T-208
T-209
T-210
T-211
T-212
T-213
T-214
T-215
T-216
T-217
T-218
T-219
T-220
T-221
T-222
T-223
T-224
T-225
T-226
T-227
T-228
T-229
T-230
T-231
T-232
T-233
T-234
T-235
T-236
T-237
T-238
T-239
T-240
T-241
T-242
T-243
T-244
T-245
T-246
T-247
T-248
T-249
T-250
T-251
T-252
T-253
T-254
T-255
T-256
T-257
T-258
T-259
T-260
T-261
T-262
T-263
T-264
T-265
T-266
T-267
T-268
T-269
T-270
T-271
T-272
T-273
T-274
T-275
T-276
T-277
T-278
T-279
T-280
T-281
Task-Template
Tasks
agent-context
api
clean-state-checklist
current-state
routes
Clone
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-252.md· commitafc651f75a3a
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。任何路径都不得进入购物车、订单提交或支付。
方案
- 新增透明
PinduoduoClipboardRelayActivity和进程内 broker,以窗口焦点、时间戳、 单项剪贴板和 PDD URL allowlist 验证复制结果。 - 将候选 driver 的身份解析改为 sealed result,并让短链 resolver 区分格式、网络和 无法解析;workflow 将原因映射为稳定失败码。
- 扩展候选证据和 progress store 支持空平台身份及身份失败码,resolved/diagnostic 分开计数、去重和排序;终态前才附加 diagnostic observation。
- 扩展 terminal policy,使确定性的剪贴板基础设施故障可以在未耗尽三轮时关闭 gate 并排队终态。
- 增加纯 Kotlin 单测、Android 构建验证,并在 PKG110 上验证复制、前台读取、短链 解析、返回详情页和 Admin 候选结果。
验收要点
- Android 16/ColorOS 上前台中继可读取新复制的 PDD 白名单链接,不再使用后台 accessibility service 读取剪贴板。
- 中继读取结果交给受限短链解析器生成唯一
goods_id和规范商品 URL,完成后 自动关闭并恢复前一个 Activity。 - 两个身份完整候选仍按 resolved 数量增量回传并进入 Admin 等待确认。
- 身份失败时最多保留两个不可下单观察及其标题、SKU、价格和两张证据图,并在 终态前作为无采集元数据的 partial snapshot 回传。
- 未解析观察不计入成功数量,空平台身份沿用后端禁止创建下单授权的边界。
- 确定性剪贴板基础设施故障首轮进入终态,不重复三轮图片搜索。
- 原始剪贴板文本不落盘、不入日志、不上传。
- 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 授权处于启用状态;未进入购物车、提交或支付。