fix(android): 规格面板纵向滚动区域放宽为高度不小于宽度的 80%(PURCHASE_ADDRESS_ENTRY_AMBIGUOUS) #390

Open
opened 2026-10-13 17:32:42 +08:00 by ila · 2 comments
Owner

基本信息

  • 类型:缺陷修复(仅 Android Agent),采购流程中的规格面板滚动区域识别。采购流程相关,属高风险类别:装机和真机下单验证须用户另行授权。
  • 状态:代码已提交推送,待验收;未合并、未发布、未装机。
  • 建单:Gitea MCP 不可用,回退 REST。
  • 来源:2026-10-13 用户要求「分析线上服务syb261011BPTYSW1E订单采购失败的原因」,看过分析后回复「按照最小化修改方案来建工单」。
  • 关联:#65(引入「高度不小于宽度」条件,提交 f5ac7f6)、#388(地址保存后放行证据齐全的快捷确认面板,已合并 main,待验收)、#364/#370(采购失败现场快照)。

已核验事实(线上只读查询、origin/main b2285c8,2026-10-13)

失败任务

  • 采购任务 #2865(SYB 订单 syb261011BPTYSW1E),设备 8(采购1),Agent 0.9.71。14:53:11–14:53:30 规格探测完成,14:53:30 进入采购,14:53:35 失败:PURCHASE_ADDRESS_ENTRY_AMBIGUOUS「没有找到唯一的规格面板滚动区域,未创建订单」。没有修改地址,也没有创建订单。
  • 失败快照 id 214。已在本机用 Agent 自身的判断代码离线回放,只输出结构化结果;快照和本机测试已删除,未提交。

离线回放结果

  • 前台为 PDD NewPageActivity,面板被识别为 ORDER_CONFIRMATION(采购接受的类型),规格选项展开(2 个维度、9 个选项),有支付方式、唯一数量输入框和底部下单行(finalSubmitTargets 返回 1 个)。
  • 收货地址入口:节点树中有 1 个打码手机号节点,但不可见、高度为 0。它位于规格列表之外、面板顶部的区域,推测是规格探测阶段滑动后,顶部可折叠区域被收起。resolveAddressEntries:phoneNodes=0;addressCards=0;tapTargets=0。
  • 按 updateShippingAddress()(PurchaseLiveAutomation.kt:144),看不到地址入口时应在唯一的面板滚动区域内向下滑动。页面上只有 1 个可滚动节点:规格列表 RecyclerView,宽 1080、高 1078(屏幕 1080×2376,宽度占 100%,高度占 45%)。
  • purchasePanelScrollTargets()(:795)要求 height >= width、宽度 ≥ 屏幕 60%、高度 ≥ 屏幕 20%。该列表高度比宽度小 2 像素而被排除,滚动区域个数为 0,一次都没滑就失败了。

出现频率

  • PURCHASE_ADDRESS_ENTRY_AMBIGUOUS 历史共 4 次,其中「没有找到唯一的规格面板滚动区域」2 次:任务 #48(2026-09-03,采购2,无快照)和 #2865。近 7 天只有 #2865 这 1 次。
  • 同一函数还用于地址保存后停在面板时的向下滑动确认(restoreFinalEvidenceInCurrentPanel,:646),存在同样的风险。

目标

规格面板的纵向滚动列表因高度略小于宽度而无法识别时,仍能识别为唯一的面板滚动区域,从而按原有逻辑有限次向下滑动,露出收货地址入口。

非目标

  • 不改「必须唯一」、宽度 ≥ 屏幕 60%、高度 ≥ 屏幕 20% 这三项条件。
  • 不改滑动方向、距离、次数(最多 5 轮)、签名不变即停止的逻辑,以及滑动后的地址入口识别规则。
  • 不改地址修改、保存、后缀,下单按钮定位,规格、单价、数量复核,以及 #388 的面板判断。
  • 不处理「收货地址入口不唯一」(#51/#53,2026-09-03,无快照)。
  • 不改服务端、Web 和接口。

方案(最小方案)

  1. purchasePanelScrollTargets() 中的 node.bounds.height >= node.bounds.width 改为「高度不小于宽度的 80%」:node.bounds.height * 100 >= node.bounds.width * PANEL_SCROLL_MIN_HEIGHT_TO_WIDTH_PERCENT,新增常量 PANEL_SCROLL_MIN_HEIGHT_TO_WIDTH_PERCENT = 80,并在注释中注明 #390 和原因。其余条件不变。
  2. 80% 的取舍:本例为 99.8%。面板列表高度会随顶部区域展开或收起而变化,留出余量。横向轮播、横向规格行通常高度远小于宽度,仍被排除。即使因此多出候选,「必须唯一」仍会让流程明确失败,不会滑错区域。
  3. 该函数的两处调用(:144 查找地址入口、:646 保存后在面板内确认)都会受影响,均为「露出内容」的可撤回滑动,不涉及点击下单。
  4. 版本:Agent 0.9.72(85)→ 0.9.73(86)。

设计证据

无界面变化,不需要原型。

子项目影响、依赖与并行

  • 仅 Android:automation/PurchaseLiveAutomation.kt、app/build.gradle.kts(版本号)、src/test 下的回归测试。
  • 前置依赖:基于已合并 #388 的 origin/main(b2285c8 或更新),与 #388 改的是同一文件的不同位置。#388 仍待验收;本单可以实施,但装机时会一并带上 #388 的改动。
  • 不与服务端或 Web 工单冲突。

验收标准

  • 回归测试(合成样例,不使用线上快照):
    • 规格面板纵向列表为 1080×1078(高度略小于宽度)、地址入口高度为 0 时:识别出唯一滚动区域并向下滑动;滑动后出现地址入口则继续地址修改流程;
    • 横向滚动区域(如 1080×400)仍不被当作面板滚动区域;
    • 出现两个符合条件的滚动区域时仍以 PURCHASE_ADDRESS_ENTRY_AMBIGUOUS 失败;
    • 滑动后仍找不到地址入口时,按原逻辑以 PURCHASE_ADDRESS_PANEL_TIMEOUT 明确失败;
    • 原有测试全部通过。
  • Android 单元测试全部通过,Debug 构建通过。
  • 离线复核:临时从线上只读重新导出快照 214,用修改后的代码确认能识别出唯一滚动区域;用完即删,不提交。(快照只是失败那一刻的页面,无法离线验证滑动后能否露出地址入口。)
  • 真机验证(需用户授权装机和实际下单):观察该错误是否再出现;滑动能否露出折叠起来的地址入口,需要真机确认。
  • 如实记录未验证项。

风险与回退

  • 采购流程高风险,但改动只放宽滚动区域的形状条件。影响的是点击下单之前、为露出内容所做的有限滑动;「必须唯一」、滑动次数上限和后续所有确认都不变,无法确认时仍明确失败。
  • 未证实的前提:在这个规格列表内向下滑动,能把顶部折叠起来的地址区域展开。如果不能,流程会以 PURCHASE_ADDRESS_PANEL_TIMEOUT 失败,不会更糟。
  • 离线复核会在本机临时处理含个人信息的快照;不提交、不写入工单或日志,用完即删。
  • 回退:回滚 Agent 版本。

文档影响

  • 更新 Wiki Business-Rules-and-Glossary:「纵向滚动容器」现以「高度不小于宽度的 80%」判断(#390)。
  • 其他页面无长期影响。

本轮交付结论

代码、全套Android单元测试、APK构建及文档已完成并推送。原现场仅完成脱敏几何核对,未宣称完整原树回放;真机滑动效果待用户授权验证,详见本轮实施评论。

## 基本信息 - 类型:缺陷修复(仅 Android Agent),采购流程中的规格面板滚动区域识别。**采购流程相关,属高风险类别**:装机和真机下单验证须用户另行授权。 - 状态:代码已提交推送,待验收;未合并、未发布、未装机。 - 建单:Gitea MCP 不可用,回退 REST。 - 来源:2026-10-13 用户要求「分析线上服务syb261011BPTYSW1E订单采购失败的原因」,看过分析后回复「按照最小化修改方案来建工单」。 - 关联:#65(引入「高度不小于宽度」条件,提交 `f5ac7f6`)、#388(地址保存后放行证据齐全的快捷确认面板,已合并 main,待验收)、#364/#370(采购失败现场快照)。 ## 已核验事实(线上只读查询、`origin/main` `b2285c8`,2026-10-13) ### 失败任务 - 采购任务 #2865(SYB 订单 `syb261011BPTYSW1E`),设备 8(采购1),Agent 0.9.71。14:53:11–14:53:30 规格探测完成,14:53:30 进入采购,14:53:35 失败:`PURCHASE_ADDRESS_ENTRY_AMBIGUOUS`「没有找到唯一的规格面板滚动区域,未创建订单」。没有修改地址,也没有创建订单。 - 失败快照 id 214。已在本机用 Agent 自身的判断代码离线回放,只输出结构化结果;快照和本机测试已删除,未提交。 ### 离线回放结果 - 前台为 PDD `NewPageActivity`,面板被识别为 `ORDER_CONFIRMATION`(采购接受的类型),规格选项展开(2 个维度、9 个选项),有支付方式、唯一数量输入框和底部下单行(`finalSubmitTargets` 返回 1 个)。 - 收货地址入口:节点树中有 1 个打码手机号节点,但**不可见、高度为 0**。它位于规格列表之外、面板顶部的区域,推测是规格探测阶段滑动后,顶部可折叠区域被收起。`resolveAddressEntries`:`phoneNodes=0;addressCards=0;tapTargets=0`。 - 按 `updateShippingAddress()`(`PurchaseLiveAutomation.kt:144`),看不到地址入口时应在唯一的面板滚动区域内向下滑动。页面上只有 1 个可滚动节点:规格列表 `RecyclerView`,宽 1080、高 1078(屏幕 1080×2376,宽度占 100%,高度占 45%)。 - `purchasePanelScrollTargets()`(`:795`)要求 `height >= width`、宽度 ≥ 屏幕 60%、高度 ≥ 屏幕 20%。该列表高度比宽度小 2 像素而被排除,滚动区域个数为 0,一次都没滑就失败了。 ### 出现频率 - `PURCHASE_ADDRESS_ENTRY_AMBIGUOUS` 历史共 4 次,其中「没有找到唯一的规格面板滚动区域」2 次:任务 #48(2026-09-03,采购2,无快照)和 #2865。近 7 天只有 #2865 这 1 次。 - 同一函数还用于地址保存后停在面板时的向下滑动确认(`restoreFinalEvidenceInCurrentPanel`,`:646`),存在同样的风险。 ## 目标 规格面板的纵向滚动列表因高度略小于宽度而无法识别时,仍能识别为唯一的面板滚动区域,从而按原有逻辑有限次向下滑动,露出收货地址入口。 ## 非目标 - 不改「必须唯一」、宽度 ≥ 屏幕 60%、高度 ≥ 屏幕 20% 这三项条件。 - 不改滑动方向、距离、次数(最多 5 轮)、签名不变即停止的逻辑,以及滑动后的地址入口识别规则。 - 不改地址修改、保存、后缀,下单按钮定位,规格、单价、数量复核,以及 #388 的面板判断。 - 不处理「收货地址入口不唯一」(#51/#53,2026-09-03,无快照)。 - 不改服务端、Web 和接口。 ## 方案(最小方案) 1. `purchasePanelScrollTargets()` 中的 `node.bounds.height >= node.bounds.width` 改为「高度不小于宽度的 80%」:`node.bounds.height * 100 >= node.bounds.width * PANEL_SCROLL_MIN_HEIGHT_TO_WIDTH_PERCENT`,新增常量 `PANEL_SCROLL_MIN_HEIGHT_TO_WIDTH_PERCENT = 80`,并在注释中注明 #390 和原因。其余条件不变。 2. 80% 的取舍:本例为 99.8%。面板列表高度会随顶部区域展开或收起而变化,留出余量。横向轮播、横向规格行通常高度远小于宽度,仍被排除。即使因此多出候选,「必须唯一」仍会让流程明确失败,不会滑错区域。 3. 该函数的两处调用(`:144` 查找地址入口、`:646` 保存后在面板内确认)都会受影响,均为「露出内容」的可撤回滑动,不涉及点击下单。 4. 版本:Agent 0.9.72(85)→ 0.9.73(86)。 ## 设计证据 无界面变化,不需要原型。 ## 子项目影响、依赖与并行 - 仅 Android:`automation/PurchaseLiveAutomation.kt`、`app/build.gradle.kts`(版本号)、`src/test` 下的回归测试。 - 前置依赖:基于已合并 #388 的 `origin/main`(`b2285c8` 或更新),与 #388 改的是同一文件的不同位置。#388 仍待验收;本单可以实施,但装机时会一并带上 #388 的改动。 - 不与服务端或 Web 工单冲突。 ## 验收标准 - [x] 回归测试(合成样例,不使用线上快照): - 规格面板纵向列表为 1080×1078(高度略小于宽度)、地址入口高度为 0 时:识别出唯一滚动区域并向下滑动;滑动后出现地址入口则继续地址修改流程; - 横向滚动区域(如 1080×400)仍不被当作面板滚动区域; - 出现两个符合条件的滚动区域时仍以 `PURCHASE_ADDRESS_ENTRY_AMBIGUOUS` 失败; - 滑动后仍找不到地址入口时,按原逻辑以 `PURCHASE_ADDRESS_PANEL_TIMEOUT` 明确失败; - 原有测试全部通过。 - [x] Android 单元测试全部通过,Debug 构建通过。 - [ ] 离线复核:临时从线上只读重新导出快照 214,用修改后的代码确认能识别出唯一滚动区域;用完即删,不提交。(快照只是失败那一刻的页面,无法离线验证滑动后能否露出地址入口。) - [ ] 真机验证(需用户授权装机和实际下单):观察该错误是否再出现;滑动能否露出折叠起来的地址入口,需要真机确认。 - [x] 如实记录未验证项。 ## 风险与回退 - 采购流程高风险,但改动只放宽滚动区域的形状条件。影响的是点击下单之前、为露出内容所做的有限滑动;「必须唯一」、滑动次数上限和后续所有确认都不变,无法确认时仍明确失败。 - 未证实的前提:在这个规格列表内向下滑动,能把顶部折叠起来的地址区域展开。如果不能,流程会以 `PURCHASE_ADDRESS_PANEL_TIMEOUT` 失败,不会更糟。 - 离线复核会在本机临时处理含个人信息的快照;不提交、不写入工单或日志,用完即删。 - 回退:回滚 Agent 版本。 ## 文档影响 - 更新 Wiki Business-Rules-and-Glossary:「纵向滚动容器」现以「高度不小于宽度的 80%」判断(#390)。 - 其他页面无长期影响。 ## 本轮交付结论 代码、全套Android单元测试、APK构建及文档已完成并推送。原现场仅完成脱敏几何核对,未宣称完整原树回放;真机滑动效果待用户授权验证,详见本轮实施评论。
Author
Owner

2026-10-13 开始实施:用户授权执行 #389/#390,完成后通知 Claude。#390 基于 origin/main b2285c8 在独立 worktree issue-390 实施,仅修改约定的滚动区域比例、版本及合成回归测试,先验证测试失败再最小修复。保留 #388 所有行为。实施不包含安装、真机修改地址/下单、合并或线上发布。线上原始快照的处理需服从仓库隐私规则,不把现有工单的临时落盘描述视为越过安全规则的授权;优先内存处理、只输出结构化证据,无法安全取得则如实标明未验证。

2026-10-13 开始实施:用户授权执行 #389/#390,完成后通知 Claude。#390 基于 origin/main b2285c8 在独立 worktree issue-390 实施,仅修改约定的滚动区域比例、版本及合成回归测试,先验证测试失败再最小修复。保留 #388 所有行为。实施不包含安装、真机修改地址/下单、合并或线上发布。线上原始快照的处理需服从仓库隐私规则,不把现有工单的临时落盘描述视为越过安全规则的授权;优先内存处理、只输出结构化证据,无法安全取得则如实标明未验证。
Author
Owner

实施完成,待验收(2026-10-13)

实现

  • 基线 b2285c8394f3fe19806aab58dd7d4882e3bbd9b1。
  • 分支 fix/390-panel-scroll-ratio 已推送;实现 a3c05a751ba7674ca512931d16bff73604bb40d2,联合镜像文档 0dfe8406c404a0b2f87acaaf1c22fb68d0991c9e(来自 #389 同内容文档提交,无代码依赖)。
  • purchasePanelScrollTargets 仅将高宽比门槛改为 >=80%,增加命名常量及原因注释;visible/enabled/scrollable、屏幕宽度>=60%、高度>=20%、候选唯一条件不变。
  • 地址修改前与保存后两处调用复用该函数。DOWN、350ms、最多5轮和签名不变停止保持原样;不改规格/数量/价格/下单验证,不点击付款。
  • 版本 0.9.73(86)。

验证

  • 新增 8 项测试,覆盖 1080×1078、80% 边界及边界下方、横向 1080×400、屏幕大小约束、多候选拒绝、未变化/有界超时和地址保存后恢复。TDD 原实现出现预期 5 项失败,修复后 PurchaseLiveAutomationTest 92/92 通过。
  • gradlew.bat test assembleDebug 成功:Debug 82 suites / 840 tests,Release 80 suites / 827 tests,均零失败、零错误、零跳过;Debug APK 构建通过。
  • 独立规格与代码质量审核通过;主代理复核测试 XML、版本及 APK SHA256。
  • 对原失败快照在服务端内存只读解析,只输出脱敏结构几何:1080×2376 屏幕、唯一可见启用的可滚动区域 1080×1078;旧高宽比拒绝、新比例接受,屏幕比例条件均满足。未导出/落盘原树。
  • 上述属于原现场结构核对 + 合成样例执行实际代码,不等于完整原始快照的 Kotlin 离线回放,也不能证明真实滑动会展开地址。 完整回放及真机验收未完成,不勾选对应验收项。没有执行手机操作。

APK

  • D:/OPC/goauto-worktrees/issue-390/android/app/build/outputs/apk/debug/app-debug.apk,6,604,611 bytes。
  • SHA256:D6CE472E8035E0AC9D14C89DD3B74C544A8C28563488D5535B5D6E2032C9FD14。
  • 使用已有 D:/OPC/goauto/debug.keystore,证书 SHA256 bf86d7465c6092be74ce9c4187eb30c9a7d045c3b91891a547e2598429766dec;未覆盖安装。

文档与交付边界

  • Wiki 已在线更新并回读:Business-Rules-and-Glossary revision e937060afcf088930d8ec3cda537ef1199265e74;SYB-ERP-Interface-Contract revision 3f44b3ed91ff19c592bba4e2dbbef28d971633da。
  • 已执行一轮 python dev_scripts/harness.py sync 与 sync --check,17 个页面一致性通过。两分支采用同一份联合 Wiki 镜像,避免相互覆盖。
  • check --strict 未通过:基线已有未登记镜像 docs/evidence/pdd-home-35727-summary.md;已确认该文件在基线存在,本次未修改,不扩展修复范围。git diff --check 通过。
  • 未合并 main、未部署/重启、未安装 APK、未执行真机采购/付款、未修改或重同步生产数据。本次无新增业务库迁移。
  • 工单保持开放、待用户验收。分支尚未合并,两工单 worktree 保留;最终工作区均干净。
## 实施完成,待验收(2026-10-13) ### 实现 - 基线 `b2285c8394f3fe19806aab58dd7d4882e3bbd9b1`。 - 分支 `fix/390-panel-scroll-ratio` 已推送;实现 `a3c05a751ba7674ca512931d16bff73604bb40d2`,联合镜像文档 `0dfe8406c404a0b2f87acaaf1c22fb68d0991c9e`(来自 #389 同内容文档提交,无代码依赖)。 - `purchasePanelScrollTargets` 仅将高宽比门槛改为 >=80%,增加命名常量及原因注释;visible/enabled/scrollable、屏幕宽度>=60%、高度>=20%、候选唯一条件不变。 - 地址修改前与保存后两处调用复用该函数。DOWN、350ms、最多5轮和签名不变停止保持原样;不改规格/数量/价格/下单验证,不点击付款。 - 版本 0.9.73(86)。 ### 验证 - 新增 8 项测试,覆盖 1080×1078、80% 边界及边界下方、横向 1080×400、屏幕大小约束、多候选拒绝、未变化/有界超时和地址保存后恢复。TDD 原实现出现预期 5 项失败,修复后 PurchaseLiveAutomationTest 92/92 通过。 - `gradlew.bat test assembleDebug` 成功:Debug 82 suites / 840 tests,Release 80 suites / 827 tests,均零失败、零错误、零跳过;Debug APK 构建通过。 - 独立规格与代码质量审核通过;主代理复核测试 XML、版本及 APK SHA256。 - 对原失败快照在服务端内存只读解析,只输出脱敏结构几何:1080×2376 屏幕、唯一可见启用的可滚动区域 1080×1078;旧高宽比拒绝、新比例接受,屏幕比例条件均满足。未导出/落盘原树。 - **上述属于原现场结构核对 + 合成样例执行实际代码,不等于完整原始快照的 Kotlin 离线回放,也不能证明真实滑动会展开地址。** 完整回放及真机验收未完成,不勾选对应验收项。没有执行手机操作。 ### APK - `D:/OPC/goauto-worktrees/issue-390/android/app/build/outputs/apk/debug/app-debug.apk`,6,604,611 bytes。 - SHA256:`D6CE472E8035E0AC9D14C89DD3B74C544A8C28563488D5535B5D6E2032C9FD14`。 - 使用已有 `D:/OPC/goauto/debug.keystore`,证书 SHA256 `bf86d7465c6092be74ce9c4187eb30c9a7d045c3b91891a547e2598429766dec`;未覆盖安装。 ### 文档与交付边界 - Wiki 已在线更新并回读:Business-Rules-and-Glossary revision `e937060afcf088930d8ec3cda537ef1199265e74`;SYB-ERP-Interface-Contract revision `3f44b3ed91ff19c592bba4e2dbbef28d971633da`。 - 已执行一轮 `python dev_scripts/harness.py sync` 与 `sync --check`,17 个页面一致性通过。两分支采用同一份联合 Wiki 镜像,避免相互覆盖。 - `check --strict` 未通过:基线已有未登记镜像 `docs/evidence/pdd-home-35727-summary.md`;已确认该文件在基线存在,本次未修改,不扩展修复范围。`git diff --check` 通过。 - 未合并 main、未部署/重启、未安装 APK、未执行真机采购/付款、未修改或重同步生产数据。本次无新增业务库迁移。 - 工单保持开放、待用户验收。分支尚未合并,两工单 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#390