Page:
T-274
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-274.md· commitafc651f75a3a
id: T-274 title: 修复重复候选签名导致商品节点无法打开 phase: 2 deps:
- T-255
- T-271 status: DONE created: 2026-08-01 context_ref: c8c4914 work_branch: null write_paths:
- docs/tasks/T-274.md
- docs/current-state.md
- docs/04-architecture.md
- docs/05-coding-rules.md
- android-buyer/app/src/main/**
- android-buyer/app/src/test/**
问题 / 背景
真机任务三轮都在 pdd_browse_candidates 首次打开候选时返回
TRANSIENT_AUTOMATION。每轮诊断均为 cards=4 distinct=2 attempts=1 scrolls=0,且
规格、身份和 VLM 计数全部为 0。
代码确认读取阶段按标题语义生成 signature,打开阶段重新扫描后使用
filter(signature).singleOrNull() 选择节点。4 张卡片只有 2 个签名时,重复签名使
singleOrNull() 返回空,未执行 ACTION_CLICK。此外自动化用相同 signature 记录已尝试
候选,即使打开成功,同标题但不同商品的后续卡片也会被跳过。
行为契约
- 候选读取除语义 signature 外,为每张已接受卡片生成仅限当前结果视口使用的 locator: recycler child index、接受顺序、容器 bounds、点击目标相对 path,以及对完整语义、节点 class/resource/path 的 SHA-256 指纹。locator 不包含原始文本,也不进入证据、outbox、 Admin 或持久化进度。
- 打开候选时重新读取安全结果页,先同时复核 signature、完整内容指纹和原容器位置; 原位置变化时只允许通过唯一内容指纹和高比例 bounds 重叠重定位。零命中或多命中均 失败关闭,不能凭标题任取第一个节点。
- bounds 只用于验证同一节点,动作仍对唯一、可见、enabled 的无障碍节点执行一次
ACTION_CLICK;禁止坐标点击、VLM 选择或保留AccessibilityNodeInfo跨快照引用。 - 本轮尝试去重使用不含位置的完整卡片 attempt key;语义 signature 继续用于观测和证据。 同标题但完整卡片不同的商品可分别尝试,同一完整卡片在滚动后不能反复尝试。
- 打开结果必须区分
PAGE_CHANGED/LOCATOR_MISSING/LOCATOR_NOT_FOUND/LOCATOR_AMBIGUOUS/ ACTION_REJECTED;重复 signature 被 locator 成功消歧单独计数。所有结果只映射既有安全 失败边界,不把失败伪装成 SKU、身份或 VLM 错误。 - 初次候选就绪至少需要连续两次非空读取产生相同 locator stability keys,避免使用仍在
渲染的临时结构;等待受既有
candidateReadyPollLimit和轮次总预算约束。
方案
- 扩展
PinduoduoCandidateCard的可空临时 locator,并增加纯 Kotlin locator 生成、 重定位和 bounds 重叠策略。 BuyerAccessibilityService.candidateNodes()在同次树遍历中计算容器/点击目标 path 和 指纹;打开接口返回结构化 outcome,不再以 signature 的singleOrNull()点击。PinduoduoCandidateAutomation使用卡片 attempt key 去重、等待两帧稳定,并将结构化 outcome 聚合到追加诊断键,外层失败码继续保持兼容。- 用纯策略测试覆盖
cards=4 distinct=2、位置稳定、位置变化唯一重定位、重复定位、 失配和 bounds 不重叠;用自动化 fake 覆盖每种打开 outcome 和同标题不同卡片。
验收要点
- 4 张卡片只有 2 个语义 signature 时,指定卡片可由 locator 唯一打开。
- 同标题但完整语义不同的两张卡片可在同一轮分别尝试,不因 signature 去重跳过。
- locator 缺失、失配、多命中、页面变化和
ACTION_CLICK=false分别形成诊断计数。 - 页面重排或指纹变化时不按标题任点,也不使用坐标、VLM 或旧节点引用兜底。
- 旧 fake/fixture 可通过显式 locator 构造迁移,候选证据/API/数据库契约不变。
- Android Debug/Release 单测、lint 和两种 APK 构建通过。
边界
- 不重新启用图片加载硬过滤,不修改八项候选容器判定。
- 不改变三轮数量、浏览预算、SKU/价格硬约束、goods_id 或分享链接流程。
- 不修复订单 dry-run 的独立候选选择契约,不增加 VLM 调用或下单权限。
执行记录
- 2026-08-01:根据真机三轮完全相同的
cards=4 distinct=2 attempts=1诊断创建任务, 状态TODO。直接失败点为openCandidate=false;重复 signature 已被诊断证明,现有代码 尚不能区分重复签名、节点不存在和ACTION_CLICK=false。 - 2026-08-01:完成临时 locator、纯 Kotlin 重定位策略、两帧稳定读取和完整内容 attempt
key。无障碍服务重新扫描后只点击唯一节点;重复 signature 可成功消歧,位置变化仅允许
唯一指纹加 80% bounds 重叠。外层失败码保持兼容,事件追加
openPageChanged、openLocatorMissing、openLocatorNotFound、openLocatorAmbiguous、openActionRejected和openDisambiguated六个非秘密计数。 - 2026-08-01:Debug/Release 各 457 项单测、
lintDebug、assembleDebug、assembleRelease全部通过,状态改为DONE。未修改容器八项判定、三轮预算、VLM、 evidence/API/数据库或订单 dry-run;真实失败任务仍需安装本 APK 后复跑确认真机计数。