fix(android): 规格探测阶段跳过开面板后的规则滑动,并禁止点击尺码建议入口 #361

Open
opened 2026-10-06 16:52:11 +08:00 by ila · 2 comments
Owner

基本信息

  • 类型:缺陷(Android Agent 采购 / 规格探测)。
  • 阶段:代码实现、测试、文档及授权覆盖安装已完成,待真机验收。用户于 2026-10-06 授权实施、追加 Android 本地诊断字段及覆盖安装;未授权真机采购重试、合并 main 或发布线上。
  • 来源:用户报告「采购任务 #1789(cg1789)执行时点击了 PDD 商品页规格面板的『查看尺码建议』」,并配合真机复现。
  • 关联:#249(采购入口本地诊断,未合并 main)、#334(规格探测回顶滑动)、#348(无滚动目标时跳过 reveal 滑动)。

核验基线与事实

  • 代码基线:origin/main 64f0e49;设备 7「采购2」,PLY110(ColorOS),Agent 0.9.64(versionCode 77,与 main 一致),PDD 8.22.0。
  • 服务端(只读):#1789 为 live、task_type=syb_order,目标「灰色 / 4XL」,spec_source=unresolved,因此执行 spec_probe。共 5 次 attempt(16:12、16:13、16:14、16:33、16:40),均约 7 秒失败,错误 PURCHASE_SPEC_PROBE_EMPTY(规格探测未读取到任何颜色或尺码);irreversible_at 为空,无订单。
  • 真机现象(用户目视第 5 次 attempt):进入规格面板 → 向下滑动一次 → 点击「查看尺码建议」→ 进入尺码建议页。窗口焦点日志显示,新页面在失败上报前约 0.35 秒打开;失败后手机停在 PDD「尺码建议」页。
  • 该商品规格面板(只读界面结构,未保存):唯一可滚动区为规格 RecyclerView;不可点击标题「颜色分类」和「尺码」;颜色 3 个,尺码 M~4XL(带「建议多少斤」)。「尺码」标题和「查看尺码建议」被同一个可点击整行 LinearLayout 包住,点这一行的任意位置都会打开尺码建议。
  • 任务 #1789 的规则快照:openSpecPanel.swipeAfter = {count:2, direction:"up", durationMs:500, intervalMs:1000};probeSpecs 无自定义别名,使用默认 DEFAULT_COLLECTOR(colorAliases 含「颜色分类」)。

根因(代码证据 + 真机复现)

  1. 规格探测阶段也执行了开面板后的规则滑动。 PurchaseRehearsalExecutor.kt:196 对每个动作调用 applyPostAction,:1166-1199 对 OPEN_SPEC_PANEL 执行 reveal 滑动,不区分 phase。真机按同样参数模拟两次上滑后,「颜色分类」标题被滚出屏幕(颜色选项仍可见、但上方没有标题),屏幕上只剩「尺码」标题。
  2. 采集器因此认不出颜色栏,开始回顶滑动。 PddProductDetailCollector.kt 按非可点击标题划分维度;首个维度变成 size,isSpecPanelAtTop(:1611)为 false,moveSpecPanelToTop 向下滑动,这就是用户看到的「向下滑动一下」。真机模拟回顶及在顶部继续下滑,都没有打开尺码建议,所以误点发生在滑动之后的点击。
  3. 点击可落到「尺码 / 查看尺码建议」整行。 GoAutoAccessibilityService.clickFreshDetailed(:332 起,:351 while (!node.isClickable))按「文字 + 类名 + 中心偏差 ≤32px」重找目标,目标本身不可点击时会改点最近的可点击祖先。「查看尺码建议 / 尺码助手」等文字已在 excludedOptionWords(PddProductDetailCollector.kt:244)中,但只用于解析选项,未用于点击拦截(nonConfigurableClickDenylist:255 只有提交订单、确认订单、支付、付款)。
  4. 无法定位具体是哪一次点击。 规格探测路径构造采集器时没有传入 trace(AgentForegroundService.kt:697 PddProductDetailCollector(accessibility),默认 trace = {},:963);#249 的本地诊断未合并 main;该 ColorOS 设备屏蔽应用 logcat,也禁止 adb 录屏。因此「滑回顶部后哪个点击目标解析到了整行」尚未被日志证实,需在修复版本中补齐记录后复测。

方案(最小范围)

  1. spec_probe 阶段跳过 OPEN_SPEC_PANEL 的 swipeAfter。 规格探测只读取规格,采集器自带回顶和颜色复位逻辑;swipeAfter 只服务于 purchase 阶段的选规格。purchase 阶段行为保持不变。
  2. 点击硬拦截。 在 Agent 的点击入口(clickFresh 及「改点祖先」路径、手势点击路径)统一拒绝:最终实际点击的节点或其子树文字命中尺码建议类文字(复用 excludedOptionWords 中的「查看尺码建议 / 查看尺寸建议 / 尺码助手 / 尺寸助手 / 智能选码 / 选码建议」及繁体)时不点击,返回明确失败原因,不改点其他控件。不改变现有安全拦截(提交订单、支付等)。
  3. 规格探测补齐点击记录。 spec_probe 构造采集器时传入 trace,记录每次点击的来源(spec-entry / quick-confirmation / color-click)、目标类名、裁剪后的标签(≤40 字,不含地址、手机号等个人信息)、是否改点祖先及结果。由于设备屏蔽 logcat,写入 Agent 自有的本地诊断(若复用 #249 的机制,须先评估把 #249 合并进 main 的范围,或单独实现最小的白名单写入)。
  4. 文档更正。 Troubleshooting(docs/06-troubleshooting.md:89-106)把 #249 的本地诊断写成可用,但其代码未合并 main(main 中无 purchase_diagnostics 写入)。改为与实际一致的说明,或在合并 #249 后再更新。

不做

  • 不改 Server、Web、业务数据库、规则 schema、匹配算法、采购下单流程和支付相关逻辑。Android 本地诊断库 v3 追加字段是用户单独授权的例外,见实施收口。
  • 不修改已有采购规则数据(包括 #1789 规则的 swipeAfter 配置)。
  • 不用 OCR/VLM,不保存原始控件树或整屏截图。

风险

  • 跳过 spec_probe 的 swipeAfter 可能影响「必须先上滑才能露出规格」的商品探测。需用回归测试覆盖:规格区在首屏外时,采集器自身的滑动仍能找到颜色和尺码。
  • 点击拦截过宽可能误拦合法选项(例如选项文字恰好包含「建议」)。拦截应限定为整词或明确短语,并补反例测试,例如「M 建议80-100斤」这类尺码选项必须仍可点击。
  • 涉及采购执行,正式装机和真机重试需用户授权;spec_probe 阶段不会下单,但仍需在用户监看下进行。

验收标准

  • spec_probe 阶段不执行 OPEN_SPEC_PANEL 的 swipeAfter;purchase 阶段照常执行(单元测试)。
  • 任何点击(含改点祖先)若最终目标子树包含尺码建议类文字,被拒绝且返回明确原因;「M 建议80-100斤」等尺码选项不受影响(单元测试,含合成界面树:「尺码」标题与「查看尺码建议」同处一个可点击整行)。
  • 规格探测路径产生点击记录,内容只含白名单字段,不含个人信息。
  • 用户授权后,在设备 7 用同一商品重试 #1789:不再进入尺码建议页;探测能读到颜色(深灰色 / 白色 / 黑色)和尺码(M~4XL),或以明确错误失败;并能读到点击记录。
  • Troubleshooting 中 #249 的描述与代码一致。
  • 测试结果、未验证项、提交哈希、APK 版本回写工单,待用户验收。

验证方式

  • Android 单元测试(执行器 phase 分支、点击拦截、trace 白名单),以及 .\scripts\verify.ps1 -Component android 或等效构建。
  • 真机:用户授权后安装新版本,在用户监看下重试 #1789 规格探测;读取 Agent 自有诊断记录,用后删除本地副本。

文档影响

  • 更新 Wiki「Troubleshooting」中采购诊断章节(#249 实际状态与本单新增的探测点击记录读取方式)。
  • 业务规则:补一句「规格探测阶段不执行开面板后的规则滑动;尺码建议类入口禁止点击」。
  • 先改线上 Wiki 并回读 revision,再执行一次 sync 与 sync --check。

备注

  • 本单由 Claude Code 依据只读查询、代码阅读和用户配合的真机复现整理;建单使用 Gitea REST API(当前会话无 Gitea MCP)。复现期间读取的界面结构已全部删除,工单中不含收货人、地址、订单号等个人信息。

方案补充与更正(2026-10-06,Claude Code,用户确认补充)

依据:Codex 在 SynapBus #goauto 消息 #62 中的审核意见,以及 Claude Code 对 origin/main 64f0e49 的再次核对。以下内容覆盖正文中对应的描述。

一、对正文的两处更正

  1. main 已有本地诊断,只是规格探测路径没接上。 正文「#249 本地诊断未合并 main」本身无误,但不能由此推出 main 没有本地诊断:main 已有 AgentDiagnosticStore / SafeAgentDiagnosticRecorder(android/.../persistence/AgentDiagnosticStore.kt,设备上为 goauto_diagnostics.db)。采集任务会传入 taskId 和诊断记录器;规格探测路径 AgentForegroundService.kt:697 只调用 PddProductDetailCollector(accessibility),trace、taskId(默认 0)、diagnostic 都用默认值,所以连现有诊断也会被跳过(采集器内 if (taskId <= 0) return)。
  2. 重试 #1789 并非只到探测为止。 探测成功、匹配通过后,applySpecDecision 会把任务改回「待执行」(server/app/goauto/purchase/lifecycle.go:624),设备下次领取即进入 purchase 阶段正式下单。2026-10-06 的两次真机重试因探测失败才停住,没有产生订单;此前「重试只是探测、不会下单」的说法不完整。

二、根因表述调整

  • 代码事实: ① spec_probe 阶段也会执行 OPEN_SPEC_PANEL 的 swipeAfter(PurchaseRehearsalExecutor.kt:196 → :1166);② clickFreshDetailed 在目标不可点击时会改点可点击祖先(GoAutoAccessibilityService.kt:351)。
  • 真机复现事实: 两次上滑后「颜色分类」标题滚出屏幕;回顶下滑及在顶部继续下滑都没有打开尺码建议。
  • 推断(尚未证实): 滑动之后的某次点击解析到了「尺码 / 查看尺码建议」整行。真机模拟滑动没有触发,不能单独证明原 attempt 的全部因果链;须在修复版本补齐结构化记录后闭环验证。

三、方案细化(采纳 Codex 意见)

  1. 跳过滑动的条件: 仅当 phase == spec_probe 且 动作为 OPEN_SPEC_PANEL 时跳过 swipeAfter;保留 waitAfterMs 和原有稳定等待;purchase 阶段行为不变。回归「规格在首屏外、需采集器自行滚动才能发现」的场景。
  2. 点击保护:
    • 判断范围是最终实际被点击的控件及接收点击的可点击祖先容器。不能因为同一面板其他位置出现建议入口,就拦截全部选项。
    • 直接点击、改点祖先、手势点击使用一致的判断;手势点击要按实际接收点击的父容器判断,不能只看标题叶节点。
    • 一旦拒绝,不再走手势兜底,也不改点其他控件。
    • 只匹配明确的入口短语(查看尺码建议 / 查看尺寸建议 / 尺码助手 / 尺寸助手 / 智能选码 / 选码建议及繁体),不按「建议」泛化;「M 建议80-100斤」这类选项必须通过。
    • 合成树测试:尺码标题与建议入口同在一个可点击整行;合法选项与建议入口同处一个面板;拒绝后不触发 fallback。
  3. 诊断记录:
    • 复用 main 现有的 AgentDiagnosticStore / SafeAgentDiagnosticRecorder 和诊断队列,不为此整体合并 #249,不引入新的诊断框架。
    • 规格探测路径接入 taskId、attempt、设备和规则快照的关联。
    • 记录点击来源(spec-entry / quick-confirmation / color-click 等)、候选数、祖先层级、结果和拒绝原因枚举。
    • 不持久化原始 trace、标签或控件树(截断 40 字不等于脱敏),只存白名单结构字段。
    • 明确容量、保留期限和读取方式;写入失败不影响业务结果。现有字段不足时,先在工单写明最小适配范围。
  4. 文档: Troubleshooting 按实际集成状态更正:#249 的 purchase_diagnostics 未合并;main 已有 goauto_diagnostics.db 诊断;写明本单新增记录的读取方式。

四、验收与真机验证边界(覆盖正文)

  • 正常商品(本例:颜色深灰色 / 白色 / 黑色,尺码 M~4XL)必须读到预期的颜色和尺码,且不进入尺码建议页,才算修复成功。「以明确错误失败」只是异常情况下的保护验收,不能当作修复成功。
  • 必须回归:原本正常的采购流程、带合法体重说明的尺码选项、规格在首屏外的商品。
  • 真机验证不得直接重试正式任务 #1789:探测成功后会自动进入正式下单。建议用同一商品新建 rehearsal(演练)模式的采购任务验证。服务端 MarkOrderSubmitStarted 会拒绝非 live 任务进入下单边界(lifecycle.go:276 起,「演练任务不能创建订单」)。能否为该 SYB 明细创建演练任务,由实施方先核实;若只能用正式任务验证,必须事先取得用户对创建订单的单独授权。
  • 装 APK、真机重试仍需用户另行授权。

实施收口(2026-10-06,用户授权补齐并实施)

以下补充及评论 #8872 覆盖正文的旧方案。本轮仅编码、自动化测试、分支提交推送及文档闭环;不合并 main、不发布、不安装 APK、不重试正式任务。

  1. 诊断关联:复用 AgentDiagnosticStore/SafeAgentDiagnosticRecorder;明确区分 collection/purchase,采购记录绑定 taskId、服务端 taskAttemptId、deviceId、phase、ruleSnapshot SHA-256。现有 attempt 为动作内次数,不作采购 attemptId 使用。禁止直接持久化 trace/原始标签。现有 SQLite 无上述关联列;拟只做可空字段的向后兼容追加,不更改旧记录和业务库,用户于 2026-10-06 已明确授权追加本地诊断字段及以后安装新版时自动升级。版本 v3 只追加可空 task_type/task_attempt_id/device_id/phase/rule_snapshot_hash;V1/V2 原数据保留,旧记录不猜测归属。容量沿用现有全库最近50条、7天,输出仅白名单结构字段,诊断失败不影响执行。
  2. 安全真机验证:当前演练按 PDD 商品建立,不会自动绑定指定 SYB 明细;档案确定性匹配成功可能绕过 spec_probe。验证前必须确认实际 phase=spec_probe 和匹配规则,不能把演练完成当作探测已覆盖;不修改线上商品/规则来强制走分支。优先用本地合成任务/测试覆盖探测,真机方案另行核定授权。正式任务探测成功后可进入下单,不直接重试作只读验证。
  3. 开发基线 origin/main 64f0e49,独立 worktree issue-361。恢复既有行为的 Android 缺陷,无新增 UI,复用已有交互;无前置合并 #249 的依赖。不改 Server/Web/服务端数据库/规则数据/订单提交路径。
  4. Gitea MCP 当前不可用,本轮工单和必要 Wiki 操作回退 REST API;凭据仅从用户私有配置读取。
## 基本信息 - 类型:缺陷(Android Agent 采购 / 规格探测)。 - 阶段:代码实现、测试、文档及授权覆盖安装已完成,待真机验收。用户于 2026-10-06 授权实施、追加 Android 本地诊断字段及覆盖安装;未授权真机采购重试、合并 main 或发布线上。 - 来源:用户报告「采购任务 #1789(cg1789)执行时点击了 PDD 商品页规格面板的『查看尺码建议』」,并配合真机复现。 - 关联:#249(采购入口本地诊断,**未合并 main**)、#334(规格探测回顶滑动)、#348(无滚动目标时跳过 reveal 滑动)。 ## 核验基线与事实 - 代码基线:origin/main `64f0e49`;设备 7「采购2」,PLY110(ColorOS),Agent 0.9.64(versionCode 77,与 main 一致),PDD 8.22.0。 - 服务端(只读):#1789 为 live、task_type=syb_order,目标「灰色 / 4XL」,spec_source=unresolved,因此执行 spec_probe。共 5 次 attempt(16:12、16:13、16:14、16:33、16:40),均约 7 秒失败,错误 `PURCHASE_SPEC_PROBE_EMPTY`(规格探测未读取到任何颜色或尺码);irreversible_at 为空,无订单。 - 真机现象(用户目视第 5 次 attempt):进入规格面板 → 向下滑动一次 → 点击「查看尺码建议」→ 进入尺码建议页。窗口焦点日志显示,新页面在失败上报前约 0.35 秒打开;失败后手机停在 PDD「尺码建议」页。 - 该商品规格面板(只读界面结构,未保存):唯一可滚动区为规格 RecyclerView;不可点击标题「颜色分类」和「尺码」;颜色 3 个,尺码 M~4XL(带「建议多少斤」)。「尺码」标题和「查看尺码建议」被同一个**可点击整行** LinearLayout 包住,点这一行的任意位置都会打开尺码建议。 - 任务 #1789 的规则快照:`openSpecPanel.swipeAfter = {count:2, direction:"up", durationMs:500, intervalMs:1000}`;`probeSpecs` 无自定义别名,使用默认 DEFAULT_COLLECTOR(colorAliases 含「颜色分类」)。 ## 根因(代码证据 + 真机复现) 1. **规格探测阶段也执行了开面板后的规则滑动。** `PurchaseRehearsalExecutor.kt:196` 对每个动作调用 `applyPostAction`,`:1166-1199` 对 OPEN_SPEC_PANEL 执行 reveal 滑动,不区分 phase。真机按同样参数模拟两次上滑后,「颜色分类」标题被滚出屏幕(颜色选项仍可见、但上方没有标题),屏幕上只剩「尺码」标题。 2. **采集器因此认不出颜色栏,开始回顶滑动。** `PddProductDetailCollector.kt` 按非可点击标题划分维度;首个维度变成 size,`isSpecPanelAtTop`(:1611)为 false,`moveSpecPanelToTop` 向下滑动,这就是用户看到的「向下滑动一下」。真机模拟回顶及在顶部继续下滑,**都没有**打开尺码建议,所以误点发生在滑动之后的点击。 3. **点击可落到「尺码 / 查看尺码建议」整行。** `GoAutoAccessibilityService.clickFreshDetailed`(:332 起,:351 `while (!node.isClickable)`)按「文字 + 类名 + 中心偏差 ≤32px」重找目标,目标本身不可点击时会**改点最近的可点击祖先**。「查看尺码建议 / 尺码助手」等文字已在 `excludedOptionWords`(PddProductDetailCollector.kt:244)中,但只用于解析选项,**未用于点击拦截**(`nonConfigurableClickDenylist`:255 只有提交订单、确认订单、支付、付款)。 4. **无法定位具体是哪一次点击。** 规格探测路径构造采集器时没有传入 trace(`AgentForegroundService.kt:697` `PddProductDetailCollector(accessibility)`,默认 `trace = {}`,:963);#249 的本地诊断未合并 main;该 ColorOS 设备屏蔽应用 logcat,也禁止 adb 录屏。因此「滑回顶部后哪个点击目标解析到了整行」尚未被日志证实,需在修复版本中补齐记录后复测。 ## 方案(最小范围) 1. **spec_probe 阶段跳过 OPEN_SPEC_PANEL 的 swipeAfter。** 规格探测只读取规格,采集器自带回顶和颜色复位逻辑;swipeAfter 只服务于 purchase 阶段的选规格。purchase 阶段行为保持不变。 2. **点击硬拦截。** 在 Agent 的点击入口(clickFresh 及「改点祖先」路径、手势点击路径)统一拒绝:最终实际点击的节点或其子树文字命中尺码建议类文字(复用 `excludedOptionWords` 中的「查看尺码建议 / 查看尺寸建议 / 尺码助手 / 尺寸助手 / 智能选码 / 选码建议」及繁体)时不点击,返回明确失败原因,不改点其他控件。不改变现有安全拦截(提交订单、支付等)。 3. **规格探测补齐点击记录。** spec_probe 构造采集器时传入 trace,记录每次点击的来源(spec-entry / quick-confirmation / color-click)、目标类名、裁剪后的标签(≤40 字,不含地址、手机号等个人信息)、是否改点祖先及结果。由于设备屏蔽 logcat,写入 Agent 自有的本地诊断(若复用 #249 的机制,须先评估把 #249 合并进 main 的范围,或单独实现最小的白名单写入)。 4. **文档更正。** Troubleshooting(docs/06-troubleshooting.md:89-106)把 #249 的本地诊断写成可用,但其代码未合并 main(main 中无 `purchase_diagnostics` 写入)。改为与实际一致的说明,或在合并 #249 后再更新。 ## 不做 - 不改 Server、Web、业务数据库、规则 schema、匹配算法、采购下单流程和支付相关逻辑。Android 本地诊断库 v3 追加字段是用户单独授权的例外,见实施收口。 - 不修改已有采购规则数据(包括 #1789 规则的 swipeAfter 配置)。 - 不用 OCR/VLM,不保存原始控件树或整屏截图。 ## 风险 - 跳过 spec_probe 的 swipeAfter 可能影响「必须先上滑才能露出规格」的商品探测。需用回归测试覆盖:规格区在首屏外时,采集器自身的滑动仍能找到颜色和尺码。 - 点击拦截过宽可能误拦合法选项(例如选项文字恰好包含「建议」)。拦截应限定为整词或明确短语,并补反例测试,例如「M 建议80-100斤」这类尺码选项必须仍可点击。 - 涉及采购执行,正式装机和真机重试需用户授权;spec_probe 阶段不会下单,但仍需在用户监看下进行。 ## 验收标准 - [x] spec_probe 阶段不执行 OPEN_SPEC_PANEL 的 swipeAfter;purchase 阶段照常执行(单元测试)。 - [x] 任何点击(含改点祖先)若最终目标子树包含尺码建议类文字,被拒绝且返回明确原因;「M 建议80-100斤」等尺码选项不受影响(单元测试,含合成界面树:「尺码」标题与「查看尺码建议」同处一个可点击整行)。 - [x] 规格探测路径产生点击记录,内容只含白名单字段,不含个人信息。 - [ ] 用户授权后,在设备 7 用同一商品重试 #1789:不再进入尺码建议页;探测能读到颜色(深灰色 / 白色 / 黑色)和尺码(M~4XL),或以明确错误失败;并能读到点击记录。 - [x] Troubleshooting 中 #249 的描述与代码一致。 - [x] 测试结果、未验证项、提交哈希、APK 版本回写工单,待用户验收。 ## 验证方式 - Android 单元测试(执行器 phase 分支、点击拦截、trace 白名单),以及 `.\scripts\verify.ps1 -Component android` 或等效构建。 - 真机:用户授权后安装新版本,在用户监看下重试 #1789 规格探测;读取 Agent 自有诊断记录,用后删除本地副本。 ## 文档影响 - 更新 Wiki「Troubleshooting」中采购诊断章节(#249 实际状态与本单新增的探测点击记录读取方式)。 - 业务规则:补一句「规格探测阶段不执行开面板后的规则滑动;尺码建议类入口禁止点击」。 - 先改线上 Wiki 并回读 revision,再执行一次 sync 与 sync --check。 ## 备注 - 本单由 Claude Code 依据只读查询、代码阅读和用户配合的真机复现整理;建单使用 Gitea REST API(当前会话无 Gitea MCP)。复现期间读取的界面结构已全部删除,工单中不含收货人、地址、订单号等个人信息。 ## 方案补充与更正(2026-10-06,Claude Code,用户确认补充) 依据:Codex 在 SynapBus #goauto 消息 #62 中的审核意见,以及 Claude Code 对 origin/main `64f0e49` 的再次核对。以下内容覆盖正文中对应的描述。 ### 一、对正文的两处更正 1. **main 已有本地诊断,只是规格探测路径没接上。** 正文「#249 本地诊断未合并 main」本身无误,但不能由此推出 main 没有本地诊断:main 已有 `AgentDiagnosticStore` / `SafeAgentDiagnosticRecorder`(`android/.../persistence/AgentDiagnosticStore.kt`,设备上为 `goauto_diagnostics.db`)。采集任务会传入 taskId 和诊断记录器;规格探测路径 `AgentForegroundService.kt:697` 只调用 `PddProductDetailCollector(accessibility)`,`trace`、`taskId`(默认 0)、`diagnostic` 都用默认值,所以连现有诊断也会被跳过(采集器内 `if (taskId <= 0) return`)。 2. **重试 #1789 并非只到探测为止。** 探测成功、匹配通过后,`applySpecDecision` 会把任务改回「待执行」(`server/app/goauto/purchase/lifecycle.go:624`),设备下次领取即进入 **purchase 阶段正式下单**。2026-10-06 的两次真机重试因探测失败才停住,没有产生订单;此前「重试只是探测、不会下单」的说法不完整。 ### 二、根因表述调整 - **代码事实:** ① spec_probe 阶段也会执行 OPEN_SPEC_PANEL 的 swipeAfter(`PurchaseRehearsalExecutor.kt:196 → :1166`);② `clickFreshDetailed` 在目标不可点击时会改点可点击祖先(`GoAutoAccessibilityService.kt:351`)。 - **真机复现事实:** 两次上滑后「颜色分类」标题滚出屏幕;回顶下滑及在顶部继续下滑都没有打开尺码建议。 - **推断(尚未证实):** 滑动之后的某次点击解析到了「尺码 / 查看尺码建议」整行。真机模拟滑动没有触发,不能单独证明原 attempt 的全部因果链;须在修复版本补齐结构化记录后闭环验证。 ### 三、方案细化(采纳 Codex 意见) 1. **跳过滑动的条件:** 仅当 `phase == spec_probe` **且** 动作为 OPEN_SPEC_PANEL 时跳过 swipeAfter;保留 waitAfterMs 和原有稳定等待;purchase 阶段行为不变。回归「规格在首屏外、需采集器自行滚动才能发现」的场景。 2. **点击保护:** - 判断范围是**最终实际被点击的控件及接收点击的可点击祖先容器**。不能因为同一面板其他位置出现建议入口,就拦截全部选项。 - 直接点击、改点祖先、手势点击使用一致的判断;手势点击要按实际接收点击的父容器判断,不能只看标题叶节点。 - 一旦拒绝,不再走手势兜底,也不改点其他控件。 - 只匹配明确的入口短语(查看尺码建议 / 查看尺寸建议 / 尺码助手 / 尺寸助手 / 智能选码 / 选码建议及繁体),不按「建议」泛化;「M 建议80-100斤」这类选项必须通过。 - 合成树测试:尺码标题与建议入口同在一个可点击整行;合法选项与建议入口同处一个面板;拒绝后不触发 fallback。 3. **诊断记录:** - 复用 main 现有的 `AgentDiagnosticStore` / `SafeAgentDiagnosticRecorder` 和诊断队列,不为此整体合并 #249,不引入新的诊断框架。 - 规格探测路径接入 taskId、attempt、设备和规则快照的关联。 - 记录点击来源(spec-entry / quick-confirmation / color-click 等)、候选数、祖先层级、结果和拒绝原因枚举。 - **不持久化原始 trace、标签或控件树**(截断 40 字不等于脱敏),只存白名单结构字段。 - 明确容量、保留期限和读取方式;写入失败不影响业务结果。现有字段不足时,先在工单写明最小适配范围。 4. **文档:** Troubleshooting 按实际集成状态更正:#249 的 `purchase_diagnostics` 未合并;main 已有 `goauto_diagnostics.db` 诊断;写明本单新增记录的读取方式。 ### 四、验收与真机验证边界(覆盖正文) - 正常商品(本例:颜色深灰色 / 白色 / 黑色,尺码 M~4XL)必须读到预期的颜色和尺码,且不进入尺码建议页,才算修复成功。「以明确错误失败」只是异常情况下的保护验收,不能当作修复成功。 - 必须回归:原本正常的采购流程、带合法体重说明的尺码选项、规格在首屏外的商品。 - **真机验证不得直接重试正式任务 #1789**:探测成功后会自动进入正式下单。建议用同一商品新建 rehearsal(演练)模式的采购任务验证。服务端 `MarkOrderSubmitStarted` 会拒绝非 live 任务进入下单边界(`lifecycle.go:276` 起,「演练任务不能创建订单」)。能否为该 SYB 明细创建演练任务,由实施方先核实;若只能用正式任务验证,必须事先取得用户对创建订单的单独授权。 - 装 APK、真机重试仍需用户另行授权。 ## 实施收口(2026-10-06,用户授权补齐并实施) 以下补充及评论 #8872 覆盖正文的旧方案。本轮仅编码、自动化测试、分支提交推送及文档闭环;不合并 main、不发布、不安装 APK、不重试正式任务。 1. 诊断关联:复用 AgentDiagnosticStore/SafeAgentDiagnosticRecorder;明确区分 collection/purchase,采购记录绑定 taskId、服务端 taskAttemptId、deviceId、phase、ruleSnapshot SHA-256。现有 attempt 为动作内次数,不作采购 attemptId 使用。禁止直接持久化 trace/原始标签。现有 SQLite 无上述关联列;拟只做可空字段的向后兼容追加,不更改旧记录和业务库,用户于 2026-10-06 已明确授权追加本地诊断字段及以后安装新版时自动升级。版本 v3 只追加可空 task_type/task_attempt_id/device_id/phase/rule_snapshot_hash;V1/V2 原数据保留,旧记录不猜测归属。容量沿用现有全库最近50条、7天,输出仅白名单结构字段,诊断失败不影响执行。 2. 安全真机验证:当前演练按 PDD 商品建立,不会自动绑定指定 SYB 明细;档案确定性匹配成功可能绕过 spec_probe。验证前必须确认实际 phase=spec_probe 和匹配规则,不能把演练完成当作探测已覆盖;不修改线上商品/规则来强制走分支。优先用本地合成任务/测试覆盖探测,真机方案另行核定授权。正式任务探测成功后可进入下单,不直接重试作只读验证。 3. 开发基线 origin/main 64f0e49,独立 worktree issue-361。恢复既有行为的 Android 缺陷,无新增 UI,复用已有交互;无前置合并 #249 的依赖。不改 Server/Web/服务端数据库/规则数据/订单提交路径。 4. Gitea MCP 当前不可用,本轮工单和必要 Wiki 操作回退 REST API;凭据仅从用户私有配置读取。
Author
Owner

方案补充与更正(2026-10-06,Claude Code,用户确认补充)

依据:Codex 在 SynapBus #goauto 消息 #62 中的审核意见,以及 Claude Code 对 origin/main 64f0e49 的再次核对。以下内容覆盖正文中对应的描述。

一、对正文的两处更正

  1. main 已有本地诊断,只是规格探测路径没接上。 正文「#249 本地诊断未合并 main」本身无误,但不能由此推出 main 没有本地诊断:main 已有 AgentDiagnosticStore / SafeAgentDiagnosticRecorder(android/.../persistence/AgentDiagnosticStore.kt,设备上为 goauto_diagnostics.db)。采集任务会传入 taskId 和诊断记录器;规格探测路径 AgentForegroundService.kt:697 只调用 PddProductDetailCollector(accessibility),trace、taskId(默认 0)、diagnostic 都用默认值,所以连现有诊断也会被跳过(采集器内 if (taskId <= 0) return)。
  2. 重试 #1789 并非只到探测为止。 探测成功、匹配通过后,applySpecDecision 会把任务改回「待执行」(server/app/goauto/purchase/lifecycle.go:624),设备下次领取即进入 purchase 阶段正式下单。2026-10-06 的两次真机重试因探测失败才停住,没有产生订单;此前「重试只是探测、不会下单」的说法不完整。

二、根因表述调整

  • 代码事实: ① spec_probe 阶段也会执行 OPEN_SPEC_PANEL 的 swipeAfter(PurchaseRehearsalExecutor.kt:196 → :1166);② clickFreshDetailed 在目标不可点击时会改点可点击祖先(GoAutoAccessibilityService.kt:351)。
  • 真机复现事实: 两次上滑后「颜色分类」标题滚出屏幕;回顶下滑及在顶部继续下滑都没有打开尺码建议。
  • 推断(尚未证实): 滑动之后的某次点击解析到了「尺码 / 查看尺码建议」整行。真机模拟滑动没有触发,不能单独证明原 attempt 的全部因果链;须在修复版本补齐结构化记录后闭环验证。

三、方案细化(采纳 Codex 意见)

  1. 跳过滑动的条件: 仅当 phase == spec_probe 且 动作为 OPEN_SPEC_PANEL 时跳过 swipeAfter;保留 waitAfterMs 和原有稳定等待;purchase 阶段行为不变。回归「规格在首屏外、需采集器自行滚动才能发现」的场景。
  2. 点击保护:
    • 判断范围是最终实际被点击的控件及接收点击的可点击祖先容器。不能因为同一面板其他位置出现建议入口,就拦截全部选项。
    • 直接点击、改点祖先、手势点击使用一致的判断;手势点击要按实际接收点击的父容器判断,不能只看标题叶节点。
    • 一旦拒绝,不再走手势兜底,也不改点其他控件。
    • 只匹配明确的入口短语(查看尺码建议 / 查看尺寸建议 / 尺码助手 / 尺寸助手 / 智能选码 / 选码建议及繁体),不按「建议」泛化;「M 建议80-100斤」这类选项必须通过。
    • 合成树测试:尺码标题与建议入口同在一个可点击整行;合法选项与建议入口同处一个面板;拒绝后不触发 fallback。
  3. 诊断记录:
    • 复用 main 现有的 AgentDiagnosticStore / SafeAgentDiagnosticRecorder 和诊断队列,不为此整体合并 #249,不引入新的诊断框架。
    • 规格探测路径接入 taskId、attempt、设备和规则快照的关联。
    • 记录点击来源(spec-entry / quick-confirmation / color-click 等)、候选数、祖先层级、结果和拒绝原因枚举。
    • 不持久化原始 trace、标签或控件树(截断 40 字不等于脱敏),只存白名单结构字段。
    • 明确容量、保留期限和读取方式;写入失败不影响业务结果。现有字段不足时,先在工单写明最小适配范围。
  4. 文档: Troubleshooting 按实际集成状态更正:#249 的 purchase_diagnostics 未合并;main 已有 goauto_diagnostics.db 诊断;写明本单新增记录的读取方式。

四、验收与真机验证边界(覆盖正文)

  • 正常商品(本例:颜色深灰色 / 白色 / 黑色,尺码 M~4XL)必须读到预期的颜色和尺码,且不进入尺码建议页,才算修复成功。「以明确错误失败」只是异常情况下的保护验收,不能当作修复成功。
  • 必须回归:原本正常的采购流程、带合法体重说明的尺码选项、规格在首屏外的商品。
  • 真机验证不得直接重试正式任务 #1789:探测成功后会自动进入正式下单。建议用同一商品新建 rehearsal(演练)模式的采购任务验证。服务端 MarkOrderSubmitStarted 会拒绝非 live 任务进入下单边界(lifecycle.go:276 起,「演练任务不能创建订单」)。能否为该 SYB 明细创建演练任务,由实施方先核实;若只能用正式任务验证,必须事先取得用户对创建订单的单独授权。
  • 装 APK、真机重试仍需用户另行授权。
## 方案补充与更正(2026-10-06,Claude Code,用户确认补充) 依据:Codex 在 SynapBus #goauto 消息 #62 中的审核意见,以及 Claude Code 对 origin/main `64f0e49` 的再次核对。以下内容覆盖正文中对应的描述。 ### 一、对正文的两处更正 1. **main 已有本地诊断,只是规格探测路径没接上。** 正文「#249 本地诊断未合并 main」本身无误,但不能由此推出 main 没有本地诊断:main 已有 `AgentDiagnosticStore` / `SafeAgentDiagnosticRecorder`(`android/.../persistence/AgentDiagnosticStore.kt`,设备上为 `goauto_diagnostics.db`)。采集任务会传入 taskId 和诊断记录器;规格探测路径 `AgentForegroundService.kt:697` 只调用 `PddProductDetailCollector(accessibility)`,`trace`、`taskId`(默认 0)、`diagnostic` 都用默认值,所以连现有诊断也会被跳过(采集器内 `if (taskId <= 0) return`)。 2. **重试 #1789 并非只到探测为止。** 探测成功、匹配通过后,`applySpecDecision` 会把任务改回「待执行」(`server/app/goauto/purchase/lifecycle.go:624`),设备下次领取即进入 **purchase 阶段正式下单**。2026-10-06 的两次真机重试因探测失败才停住,没有产生订单;此前「重试只是探测、不会下单」的说法不完整。 ### 二、根因表述调整 - **代码事实:** ① spec_probe 阶段也会执行 OPEN_SPEC_PANEL 的 swipeAfter(`PurchaseRehearsalExecutor.kt:196 → :1166`);② `clickFreshDetailed` 在目标不可点击时会改点可点击祖先(`GoAutoAccessibilityService.kt:351`)。 - **真机复现事实:** 两次上滑后「颜色分类」标题滚出屏幕;回顶下滑及在顶部继续下滑都没有打开尺码建议。 - **推断(尚未证实):** 滑动之后的某次点击解析到了「尺码 / 查看尺码建议」整行。真机模拟滑动没有触发,不能单独证明原 attempt 的全部因果链;须在修复版本补齐结构化记录后闭环验证。 ### 三、方案细化(采纳 Codex 意见) 1. **跳过滑动的条件:** 仅当 `phase == spec_probe` **且** 动作为 OPEN_SPEC_PANEL 时跳过 swipeAfter;保留 waitAfterMs 和原有稳定等待;purchase 阶段行为不变。回归「规格在首屏外、需采集器自行滚动才能发现」的场景。 2. **点击保护:** - 判断范围是**最终实际被点击的控件及接收点击的可点击祖先容器**。不能因为同一面板其他位置出现建议入口,就拦截全部选项。 - 直接点击、改点祖先、手势点击使用一致的判断;手势点击要按实际接收点击的父容器判断,不能只看标题叶节点。 - 一旦拒绝,不再走手势兜底,也不改点其他控件。 - 只匹配明确的入口短语(查看尺码建议 / 查看尺寸建议 / 尺码助手 / 尺寸助手 / 智能选码 / 选码建议及繁体),不按「建议」泛化;「M 建议80-100斤」这类选项必须通过。 - 合成树测试:尺码标题与建议入口同在一个可点击整行;合法选项与建议入口同处一个面板;拒绝后不触发 fallback。 3. **诊断记录:** - 复用 main 现有的 `AgentDiagnosticStore` / `SafeAgentDiagnosticRecorder` 和诊断队列,不为此整体合并 #249,不引入新的诊断框架。 - 规格探测路径接入 taskId、attempt、设备和规则快照的关联。 - 记录点击来源(spec-entry / quick-confirmation / color-click 等)、候选数、祖先层级、结果和拒绝原因枚举。 - **不持久化原始 trace、标签或控件树**(截断 40 字不等于脱敏),只存白名单结构字段。 - 明确容量、保留期限和读取方式;写入失败不影响业务结果。现有字段不足时,先在工单写明最小适配范围。 4. **文档:** Troubleshooting 按实际集成状态更正:#249 的 `purchase_diagnostics` 未合并;main 已有 `goauto_diagnostics.db` 诊断;写明本单新增记录的读取方式。 ### 四、验收与真机验证边界(覆盖正文) - 正常商品(本例:颜色深灰色 / 白色 / 黑色,尺码 M~4XL)必须读到预期的颜色和尺码,且不进入尺码建议页,才算修复成功。「以明确错误失败」只是异常情况下的保护验收,不能当作修复成功。 - 必须回归:原本正常的采购流程、带合法体重说明的尺码选项、规格在首屏外的商品。 - **真机验证不得直接重试正式任务 #1789**:探测成功后会自动进入正式下单。建议用同一商品新建 rehearsal(演练)模式的采购任务验证。服务端 `MarkOrderSubmitStarted` 会拒绝非 live 任务进入下单边界(`lifecycle.go:276` 起,「演练任务不能创建订单」)。能否为该 SYB 明细创建演练任务,由实施方先核实;若只能用正式任务验证,必须事先取得用户对创建订单的单独授权。 - 装 APK、真机重试仍需用户另行授权。
Author
Owner

实施结果(2026-10-06,待真机验收)

实现与提交

  • 基线 origin/main 64f0e49;分支 fix/361-spec-probe-click,已提交并推送:
    • a49dc69:Android 修复、诊断 v3、测试及版本。
    • 75ab256:Wiki 同步镜像。
  • 只在 spec_probe + OPEN_SPEC_PANEL 跳过 swipeAfter,保留 waitAfterMs;purchase 原滑动保留。
  • SizeAdviceClickPolicy 检查最终接收点击的控件/最近可点击祖先的子树,直接点击和手势使用同一策略;仅匹配明确简繁体建议入口短语,不按“建议”泛化。增加 BLOCKED 结果,规格入口/选择立即失败而不手势兜底;采集器颜色被拒绝后停止,不改点其他颜色。
  • 诊断复用既有库及异步队列,未合并 #249。探测入口点击/手势、快速恢复、颜色点击记录只含白名单结构字段,原始 trace 未接入;采购记录绑定 task_type=purchase、task_attempt_id、device_id、phase、rule_snapshot_hash,不混用动作 attempt 次数。
  • 用户已明确授权本地 SQLite v3 追加五个可空列,V1/V2 升级保留原行;旧行不猜测归属,全库50条/7天保留规则不变。旧 APK 不保证可降级打开 v3,不通过卸载清数据回退。

验证

  • 首轮全量 testDebugUnitTest:50个测试类、473项,0失败、0错误、0跳过。
  • 其后补齐未暴露可点击祖先的建议叶节点、采集器拒绝后停止、首屏外合法体重说明尺码用例,并重跑全部受影响测试:8个测试类、208项,0失败、0错误;版本更新后同样通过。
  • 覆盖:探测跳过预滑但保留等待,purchase 正常滑动/失败行为,建议整行与合法选项同面板,简繁体与 contentDescription,无可点击祖先的手势目标,拒绝后无 fallback,颜色拒绝不继续其他候选,首屏外尺码采集,白名单诊断,V1/V2 迁移保留旧数据/幂等追加/采购不同 attempt 分离。
  • assembleDebug:通过。现有 SDK XML / deprecated / unused 提示未扩展修复。
  • git diff --check:通过。
  • harness sync 和 sync --check:一轮均通过。
  • harness check --strict:存在1项基线问题:docs/evidence/pdd-home-35727-summary.md 是未登记镜像。该文件在 origin/main 和本单 HEAD blob 同为 41f74c4a467062e109d61ad1ac7f52b12755455e,当前任务未改动;不把严格检查声明为通过,也不扩展修改。

构建与授权安装

  • APK:Agent 0.9.68,versionCode 81,Debug。
  • 路径:android/app/build/outputs/apk/debug/app-debug.apk(issue-361 worktree)。
  • SHA-256:46e9f8dac179bce453cf053d6e408ec8c0a9c0c3800989e2ec6322f963a5abf8。
  • 用户授权覆盖安装一台指定无线设备。安装前读取白名单运行状态:ONLINE、没有 current_task_id;旧版本0.9.64/77。adb install -r 返回 Success,包管理器回读0.9.68/81。
  • 保留应用数据,未启动采购、未重试正式任务、未创建订单或执行付款。未验证设备端首次打开后的诊断库升级/诊断读取;安装成功不能代替这些验收。

Wiki

  • Troubleshooting:ac3a0b74704f398cec54149267089c87c8375a3e。
  • Business-Rules-and-Glossary:ec20bf476551c3dbc1d5aaa6301605bfe695e102。
  • Architecture-and-Code-Map:3165d7d419a46f41fa70a63286799deda9a8ce9f。
  • 均先在线写入、回读 revision,再同步镜像与检查。共享 API 字段不变;执行器拒绝直接返回 SIZE_ADVICE_CLICK_BLOCKED,采集器拒绝沿既有探测失败封装回传 PURCHASE_SPEC_PROBE_FAILED 并在消息保留阻断原因。

未验证与边界

  • 原故障具体哪次点击误入建议页仍需新版本真机诊断确认;合成测试不是现场修复验收。
  • 正常商品必须读取预期颜色尺码才算修复;“明确失败”只能算保护。旧任务失败不追补诊断。
  • 演练并不必然进入 spec_probe;正式任务探测成功后可能继续下单。真机测试需另行明确方案与授权。
  • 未改 Server/Web/业务库、规则数据或下单流程;未合并 main、未发布线上。工单保持打开待验收,worktree 尚未合并不能清理。
## 实施结果(2026-10-06,待真机验收) ### 实现与提交 - 基线 origin/main 64f0e49;分支 fix/361-spec-probe-click,已提交并推送: - a49dc69:Android 修复、诊断 v3、测试及版本。 - 75ab256:Wiki 同步镜像。 - 只在 spec_probe + OPEN_SPEC_PANEL 跳过 swipeAfter,保留 waitAfterMs;purchase 原滑动保留。 - SizeAdviceClickPolicy 检查最终接收点击的控件/最近可点击祖先的子树,直接点击和手势使用同一策略;仅匹配明确简繁体建议入口短语,不按“建议”泛化。增加 BLOCKED 结果,规格入口/选择立即失败而不手势兜底;采集器颜色被拒绝后停止,不改点其他颜色。 - 诊断复用既有库及异步队列,未合并 #249。探测入口点击/手势、快速恢复、颜色点击记录只含白名单结构字段,原始 trace 未接入;采购记录绑定 task_type=purchase、task_attempt_id、device_id、phase、rule_snapshot_hash,不混用动作 attempt 次数。 - 用户已明确授权本地 SQLite v3 追加五个可空列,V1/V2 升级保留原行;旧行不猜测归属,全库50条/7天保留规则不变。旧 APK 不保证可降级打开 v3,不通过卸载清数据回退。 ### 验证 - 首轮全量 testDebugUnitTest:50个测试类、473项,0失败、0错误、0跳过。 - 其后补齐未暴露可点击祖先的建议叶节点、采集器拒绝后停止、首屏外合法体重说明尺码用例,并重跑全部受影响测试:8个测试类、208项,0失败、0错误;版本更新后同样通过。 - 覆盖:探测跳过预滑但保留等待,purchase 正常滑动/失败行为,建议整行与合法选项同面板,简繁体与 contentDescription,无可点击祖先的手势目标,拒绝后无 fallback,颜色拒绝不继续其他候选,首屏外尺码采集,白名单诊断,V1/V2 迁移保留旧数据/幂等追加/采购不同 attempt 分离。 - assembleDebug:通过。现有 SDK XML / deprecated / unused 提示未扩展修复。 - git diff --check:通过。 - harness sync 和 sync --check:一轮均通过。 - harness check --strict:存在1项基线问题:docs/evidence/pdd-home-35727-summary.md 是未登记镜像。该文件在 origin/main 和本单 HEAD blob 同为 41f74c4a467062e109d61ad1ac7f52b12755455e,当前任务未改动;不把严格检查声明为通过,也不扩展修改。 ### 构建与授权安装 - APK:Agent 0.9.68,versionCode 81,Debug。 - 路径:android/app/build/outputs/apk/debug/app-debug.apk(issue-361 worktree)。 - SHA-256:46e9f8dac179bce453cf053d6e408ec8c0a9c0c3800989e2ec6322f963a5abf8。 - 用户授权覆盖安装一台指定无线设备。安装前读取白名单运行状态:ONLINE、没有 current_task_id;旧版本0.9.64/77。adb install -r 返回 Success,包管理器回读0.9.68/81。 - 保留应用数据,未启动采购、未重试正式任务、未创建订单或执行付款。未验证设备端首次打开后的诊断库升级/诊断读取;安装成功不能代替这些验收。 ### Wiki - Troubleshooting:ac3a0b74704f398cec54149267089c87c8375a3e。 - Business-Rules-and-Glossary:ec20bf476551c3dbc1d5aaa6301605bfe695e102。 - Architecture-and-Code-Map:3165d7d419a46f41fa70a63286799deda9a8ce9f。 - 均先在线写入、回读 revision,再同步镜像与检查。共享 API 字段不变;执行器拒绝直接返回 SIZE_ADVICE_CLICK_BLOCKED,采集器拒绝沿既有探测失败封装回传 PURCHASE_SPEC_PROBE_FAILED 并在消息保留阻断原因。 ### 未验证与边界 - 原故障具体哪次点击误入建议页仍需新版本真机诊断确认;合成测试不是现场修复验收。 - 正常商品必须读取预期颜色尺码才算修复;“明确失败”只能算保护。旧任务失败不追补诊断。 - 演练并不必然进入 spec_probe;正式任务探测成功后可能继续下单。真机测试需另行明确方案与授权。 - 未改 Server/Web/业务库、规则数据或下单流程;未合并 main、未发布线上。工单保持打开待验收,worktree 尚未合并不能清理。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#361