当前页面采集:颜色维度只解析到单个值(补颜色阶段诊断并对齐纵向发现能力) #124

Closed
opened 2026-08-28 09:24:48 +08:00 by ila · 11 comments
Owner

所属与来源

  • 关联工单:#101 当前页面采集、#111 尺码遍历、#112 面板证据与规格值状态分离、#113 订单确认面板回顶、#115 识别文案迁入规则、#116 门禁与校验分级。
  • 来源:用户于 2026-08-28 在 PKG110 使用最新 Agent(版本 0.9.11,仓库提交 e117fd2)执行当前页面采集后反馈:采集结果缺少颜色分类,只采到一种颜色;任务未失败,手机停留在 PDD 商品详情页。用户提出「是不是这次的颜色不是横向而是纵向的」。
  • 类型:Android Agent / PDD 规格解析与颜色遍历缺陷 + 颜色阶段诊断缺失。
  • 设计证据:不新增或调整页面、组件、导航与显示文案;不修改服务端数据库与共享 API。经用户于 2026-08-28 明确授权,仅允许 Agent 本地诊断库新增可空列并执行非破坏性 v1 → v2 增量迁移;属于内部诊断与既有采集完整性修复,无需原型。
  • 工具回退说明:本工单通过 Gitea API 创建。当前会话未提供 Gitea MCP 工具,按 AGENTS.md「Gitea 交互与工单最小读取」记录回退原因。

已证实事实

任务详情(用户读取):颜色仅 白色 一项,尺码 均码 一项,缺失项仅 reviewCount。

由此可确定:

  1. 不是文案识别问题:缺失项没有 unsupported,说明颜色标题已被正确映射为 color 维度,不属于 #115 范畴。

  2. 不是点击或采价失败:缺失项没有 selection: 与 price:,被采到的白色点击成功且价格正常。

  3. 不是「发现多个但遍历中途退出」:PddProductDetailCollector.kt:916 在点击之前就把当前行全部可见值写入结果——

    currentRow.forEach { rowColors[it.text] = rowColors[it.text] == true || it.available }
    val value = currentRow.firstOrNull { it.available && it.text !in attempted } ?: break
    

    若初始视口存在多个可见颜色值,即使随后因 PDD 重排触发 :905-913 的提前 break,结果也应包含那些值。结果只有一项,说明解析阶段产出的 color 值本身就只有 1 个。

  4. reviewCount 缺失与颜色无关,属既有独立小缺口,本工单不处理。

代码事实(提交 e117fd2 复核)

  • collectColors(:873-946)只有水平翻页:val direction = if (moveRight) SwipeDirection.LEFT else SwipeDirection.RIGHT;整个函数没有任何 SwipeDirection.UP。
  • 行数在第一帧冻结:val rowCount = colorRows(initial).size(:888),后续不再重新发现新行。
  • 对照组:collectSizes(:1016-1060)具备纵向扫描,repeat(specVerticalSwipes + 1) 循环内执行 swipeSpec(SwipeDirection.UP, anchor) 并逐屏合并。颜色与尺码的发现能力不对称。
  • swipeSpec 的横向分支(GoAutoAccessibilityService.kt:365-368)只接受 width > height 的可滚动祖先;纵向容器下取不到目标,会退回全局 swipe(SemanticTarget.SPEC_PANEL, ...),而该兜底同样按方向筛选,可能直接返回 false 导致 break。
  • 诊断缺口:AgentDiagnosticStage(persistence/AgentDiagnosticStore.kt:9-18)只有 DETAIL_ENTRY、SPEC_PANEL_ENTRY、SIZE_DISCOVERY 及分享/剪贴板相关阶段,颜色阶段没有任何诊断落库。叠加 ColorOS 默认限制 logcat,本次根因只能靠任务详情间接推断。

待证实分支(实施前必须先用诊断确认)

事实 3 把根因收敛到「解析阶段只产出 1 个 color 值」,但成因有两种,修复重点不同:

  • 分支 A · 纵向布局未覆盖:颜色纵向排列或多行网格,初始视口只露出一个值。修复重点在遍历(纵向发现)。
  • 分支 B · 未选中项未被解析为规格值:颜色横排且屏幕上可同时看到多个,但未选中项没有可点击祖先或不暴露给无障碍。修复重点在 parse 的 spec value 判定条件。

实施顺序要求:先落地第 1 项诊断并取得一次真机记录,确认属于哪个分支后再实施对应修复;两个分支的修复不得在无证据的情况下同时盲改。

目标

  1. 补齐颜色阶段结构化诊断,使后续同类问题不依赖 logcat 即可定位。
  2. 使颜色发现能力与尺码对齐:支持纵向与网格布局,行数不再在第一帧冻结。
  3. 若确认为分支 B,在不猜测节点含义的前提下修正规格值判定条件。
  4. 修复 PDD 重排导致的提前退出(与本次现象无关,但同一循环内的真实缺陷,一并处理)。
  5. 新增的滚动次数与阈值可由采集规则配置。

非目标

  • 不修改文案别名迁移(#115 已完成)与门禁校验(#116 已完成)。
  • 不实现支付;不新增点击下单、支付、地址相关动作。
  • 不修改分享、剪贴板、短链展开、goods_id 裁决、Activity 证据与前台恢复。
  • 不修改 #111 尺码遍历算法、#112 面板证据判定、#113 订单确认回顶。
  • 不使用 OCR/VLM,不保存控件树、XML 或截图,不猜测无标题归属的节点。
  • 不处理 reviewCount 缺失。
  • 不修改服务端裁决、服务端数据库与共享 API 字段;仅允许已授权的 Agent 本地 agent_diagnostic 表可空列增量迁移,不删除、不重建表、不清空旧记录。

实施方案

1. 颜色阶段诊断(先行,独立可验证)

  1. AgentDiagnosticStage 新增 COLOR_DISCOVERY;AgentDiagnosticReason 新增区分下列结果的枚举:COLOR_FOUND、COLOR_EDGE_REACHED、COLOR_SCAN_LIMIT、COLOR_ROW_REFLOWED、COLOR_SWIPE_FAILED、COLOR_CONTAINER_UNAVAILABLE、COLOR_VALUES_NOT_CLICKABLE。
  2. 记录字段:解析出的行数、每行值数量、可点击值数量、不可点击但可见的候选数量、纵向与横向滚动次数、终止原因、耗时。
  3. 不得记录颜色文案、价格、控件树、坐标原文与截图;沿用 #106 的 SafeAgentDiagnosticRecorder 旁路保护,写入失败不影响采集结果。
  4. 其中「不可点击但可见的候选数量」是区分分支 A/B 的关键字段:该值显著大于可点击值数量即为分支 B。

2. 分支 A · 纵向发现(确认后实施)

  1. 在 collectColors 中引入纵向发现循环,复用 collectSizes 的模式:滚动一屏 → 重新 colorRows() → 合并新行 → 直到稳定边界或次数上限。
  2. rowCount 改为每轮重新计算,不再于第一帧冻结;已处理行以行内容签名而非索引标识,避免滚动后索引错位。
  3. swipeSpec 横向分支增加兜底:取不到 width > height 的可滚动祖先时,不直接退回全局兜底,而是判定该维度为纵向布局并跳过横向翻页,避免无效手势与误滑。
  4. 自动布局判定:按颜色节点 bounds 的行列分布判断单行、多行网格或单列,作为默认行为。

3. 分支 B · 规格值判定(确认后实施)

  1. 修正 parse 中 spec value 的接受条件:允许「自身不可点击但存在可点击祖先」或「带明确选中语义」的节点作为规格值,并在结果中如实标记 available。
  2. 严禁放宽为「按位置猜测同容器内的兄弟节点」;无标题归属或无可点击路径的节点仍不得作为规格值。
  3. 若确认为分支 B,需同时确认这些值能否被安全点击;不能点击时按现有不完整契约提交 completed_partial,并在缺失项如实标注。

4. 重排导致的提前退出

  1. :905-913 的 rowIndex >= rows.size 分支不再直接 break:重新扫描当前所有行,对照 attempted 判断是否仍有未尝试且可用的值;确无剩余时才结束,并记录 COLOR_ROW_REFLOWED。

5. 规则参数

  1. 采集规则 limits 新增 colorVerticalSwipes(颜色纵向发现次数上限),沿用既有边界校验口径;未提供时取 specVerticalSwipes 作为默认值,保证存量规则快照不失效。
  2. collector 新增可选 colorLayout: auto | horizontal | vertical | grid,默认 auto,仅作为自动判定失灵时的临时覆盖手段。
  3. 服务端 rulecontract 同步新增校验,字段名与上下限与 Android 解析保持一致。

说明:布局不适合以规则为主力手段。当前采集规则是全局的(AgentManualCollectionSetting 指向单条规则,所有当前页面采集任务共用),而布局逐商品不同;把 colorLayout 写死会顾此失彼。因此以自动判定为主、规则覆盖为辅。

安全边界

  • 不点击相近候选、不猜测规格、不按坐标盲点;服务端仍是规格匹配的裁决方。
  • 不点击下单、支付、地址及其可点击祖先;Agent 侧不可配置的拒绝清单保持不变。
  • 诊断不记录颜色文案、价格、链接、goods_id、剪贴板、控件树与截图。
  • 不使用 OCR/VLM。
  • 不涉及创建订单、权限、并发、服务端迁移与删除数据;唯一迁移是已授权的 Agent 本地诊断库 v1 → v2 可空列增量迁移。

验收标准

诊断(可独立验收)

  • 一次真机采集后,本地诊断包含 COLOR_DISCOVERY 记录,可读出行数、每行值数、可点击值数、不可点击候选数、滚动次数与终止原因。
  • 诊断内容不含颜色文案、价格与任何原始结构数据。
  • 人为模拟诊断写入失败时,采集结果不变。

分支 A(若确认)

  • 纵向或网格排列的商品,能发现初始视口之外的颜色行,采到的颜色数与面板实际可见颜色数一致。
  • 横排商品行为不回退,颜色数与修复前一致。
  • 达到稳定边界或次数上限时正常结束,不无限滚动。

分支 B(若确认)

  • 未选中颜色项被正确解析为规格值并如实标记 available。
  • 无可点击路径的值不被点击,按不完整契约提交并在缺失项标注。

共同

  • PDD 重排导致行消失时不再直接结束,仍能继续处理剩余未尝试的值。
  • 未提供新 limits / colorLayout 的存量规则快照行为不变。
  • 尺码遍历(#111)、面板证据(#112)、订单确认回顶(#113)不回退。

验证方式

  • cd android && .\gradlew.bat :app:testDebugUnitTest :app:assembleDebug
  • 颜色遍历与布局判定的纯函数单元测试:单行横排、多行网格、单列纵向、重排后行消失四种输入。
  • go test ./app/goauto/rulecontract/...
  • 真机 PKG110:分别用一个横排多色商品与一个纵向/网格多色商品各采集一次,记录 Agent 版本、规则 ID/快照、任务号、采到的颜色数与面板实际颜色数。
  • 真机、多设备、其他 ROM 与异常路径未覆盖部分如实回写。

依赖、并行与风险

  • 前置依赖:#115(e117fd2)、#116(3619435)已合并;#112、#113 已合并。
  • 不建议与其他修改 PddProductDetailCollector 或 GoAutoAccessibilityService 手势逻辑的工单并行。
  • 风险:纵向发现循环若终止条件不当会拉长采集时间。缓解:沿用 stableEdgeReads 稳定边界与次数上限,并受规则总超时约束。
  • 风险:分支 B 的判定放宽有引入误识别的可能。缓解:只接受有可点击祖先或明确选中语义的节点,不按位置猜测。
  • 回退:还原本工单 Android 提交即可;新增规则字段为可选,存量快照不受影响。

文档影响

  • 需更新 Wiki Android-Agent-API-Contract(docs/08-agent-api-contract.md):采集规则新增 limits.colorVerticalSwipes 与 collector.colorLayout 的说明与默认值。
  • Business-Rules-and-Glossary(docs/03-business-rules-and-glossary.md):如颜色完整性判定口径发生变化则同步更新;仅补充发现能力时可记为无长期文档影响并说明原因。
  • 按 Wiki-first 门禁:先改线上页面并回读 revision,再执行一轮 sync 与一轮 sync --check,把页面与 revision 写回本工单。

状态

第 1 项诊断修订已由提交 d718c95 完成,等待 Debug APK 真机读取验收;第 2~5 项未实施。取得原问题商品的脱敏聚合证据并由用户确认分支前,不继续修改遍历、解析或手势逻辑。

## 所属与来源 - 关联工单:#101 当前页面采集、#111 尺码遍历、#112 面板证据与规格值状态分离、#113 订单确认面板回顶、#115 识别文案迁入规则、#116 门禁与校验分级。 - 来源:用户于 2026-08-28 在 PKG110 使用最新 Agent(版本 0.9.11,仓库提交 `e117fd2`)执行当前页面采集后反馈:采集结果缺少颜色分类,只采到一种颜色;任务未失败,手机停留在 PDD 商品详情页。用户提出「是不是这次的颜色不是横向而是纵向的」。 - 类型:Android Agent / PDD 规格解析与颜色遍历缺陷 + 颜色阶段诊断缺失。 - 设计证据:不新增或调整页面、组件、导航与显示文案;不修改服务端数据库与共享 API。经用户于 2026-08-28 明确授权,仅允许 Agent 本地诊断库新增可空列并执行非破坏性 v1 → v2 增量迁移;属于内部诊断与既有采集完整性修复,无需原型。 - 工具回退说明:本工单通过 Gitea API 创建。当前会话未提供 Gitea MCP 工具,按 `AGENTS.md`「Gitea 交互与工单最小读取」记录回退原因。 ## 已证实事实 任务详情(用户读取):颜色仅 `白色` 一项,尺码 `均码` 一项,缺失项仅 `reviewCount`。 由此可确定: 1. **不是文案识别问题**:缺失项没有 `unsupported`,说明颜色标题已被正确映射为 `color` 维度,不属于 #115 范畴。 2. **不是点击或采价失败**:缺失项没有 `selection:` 与 `price:`,被采到的白色点击成功且价格正常。 3. **不是「发现多个但遍历中途退出」**:`PddProductDetailCollector.kt:916` 在点击之前就把当前行全部可见值写入结果—— ```kotlin currentRow.forEach { rowColors[it.text] = rowColors[it.text] == true || it.available } val value = currentRow.firstOrNull { it.available && it.text !in attempted } ?: break ``` 若初始视口存在多个可见颜色值,即使随后因 PDD 重排触发 `:905-913` 的提前 break,结果也应包含那些值。结果只有一项,说明**解析阶段产出的 color 值本身就只有 1 个**。 4. `reviewCount` 缺失与颜色无关,属既有独立小缺口,本工单不处理。 ## 代码事实(提交 e117fd2 复核) - `collectColors`(`:873-946`)只有水平翻页:`val direction = if (moveRight) SwipeDirection.LEFT else SwipeDirection.RIGHT`;整个函数没有任何 `SwipeDirection.UP`。 - 行数在第一帧冻结:`val rowCount = colorRows(initial).size`(`:888`),后续不再重新发现新行。 - 对照组:`collectSizes`(`:1016-1060`)具备纵向扫描,`repeat(specVerticalSwipes + 1)` 循环内执行 `swipeSpec(SwipeDirection.UP, anchor)` 并逐屏合并。**颜色与尺码的发现能力不对称。** - `swipeSpec` 的横向分支(`GoAutoAccessibilityService.kt:365-368`)只接受 `width > height` 的可滚动祖先;纵向容器下取不到目标,会退回全局 `swipe(SemanticTarget.SPEC_PANEL, ...)`,而该兜底同样按方向筛选,可能直接返回 false 导致 `break`。 - 诊断缺口:`AgentDiagnosticStage`(`persistence/AgentDiagnosticStore.kt:9-18`)只有 `DETAIL_ENTRY`、`SPEC_PANEL_ENTRY`、`SIZE_DISCOVERY` 及分享/剪贴板相关阶段,**颜色阶段没有任何诊断落库**。叠加 ColorOS 默认限制 logcat,本次根因只能靠任务详情间接推断。 ## 待证实分支(实施前必须先用诊断确认) 事实 3 把根因收敛到「解析阶段只产出 1 个 color 值」,但成因有两种,修复重点不同: - **分支 A · 纵向布局未覆盖**:颜色纵向排列或多行网格,初始视口只露出一个值。修复重点在遍历(纵向发现)。 - **分支 B · 未选中项未被解析为规格值**:颜色横排且屏幕上可同时看到多个,但未选中项没有可点击祖先或不暴露给无障碍。修复重点在 `parse` 的 spec value 判定条件。 实施顺序要求:**先落地第 1 项诊断并取得一次真机记录,确认属于哪个分支后再实施对应修复**;两个分支的修复不得在无证据的情况下同时盲改。 ## 目标 1. 补齐颜色阶段结构化诊断,使后续同类问题不依赖 logcat 即可定位。 2. 使颜色发现能力与尺码对齐:支持纵向与网格布局,行数不再在第一帧冻结。 3. 若确认为分支 B,在不猜测节点含义的前提下修正规格值判定条件。 4. 修复 PDD 重排导致的提前退出(与本次现象无关,但同一循环内的真实缺陷,一并处理)。 5. 新增的滚动次数与阈值可由采集规则配置。 ## 非目标 - 不修改文案别名迁移(#115 已完成)与门禁校验(#116 已完成)。 - 不实现支付;不新增点击下单、支付、地址相关动作。 - 不修改分享、剪贴板、短链展开、goods_id 裁决、Activity 证据与前台恢复。 - 不修改 #111 尺码遍历算法、#112 面板证据判定、#113 订单确认回顶。 - 不使用 OCR/VLM,不保存控件树、XML 或截图,不猜测无标题归属的节点。 - 不处理 `reviewCount` 缺失。 - 不修改服务端裁决、服务端数据库与共享 API 字段;仅允许已授权的 Agent 本地 `agent_diagnostic` 表可空列增量迁移,不删除、不重建表、不清空旧记录。 ## 实施方案 ### 1. 颜色阶段诊断(先行,独立可验证) 1. `AgentDiagnosticStage` 新增 `COLOR_DISCOVERY`;`AgentDiagnosticReason` 新增区分下列结果的枚举:`COLOR_FOUND`、`COLOR_EDGE_REACHED`、`COLOR_SCAN_LIMIT`、`COLOR_ROW_REFLOWED`、`COLOR_SWIPE_FAILED`、`COLOR_CONTAINER_UNAVAILABLE`、`COLOR_VALUES_NOT_CLICKABLE`。 2. 记录字段:解析出的行数、每行值数量、可点击值数量、不可点击但可见的候选数量、纵向与横向滚动次数、终止原因、耗时。 3. **不得记录颜色文案、价格、控件树、坐标原文与截图**;沿用 #106 的 `SafeAgentDiagnosticRecorder` 旁路保护,写入失败不影响采集结果。 4. 其中「不可点击但可见的候选数量」是区分分支 A/B 的关键字段:该值显著大于可点击值数量即为分支 B。 ### 2. 分支 A · 纵向发现(确认后实施) 5. 在 `collectColors` 中引入纵向发现循环,复用 `collectSizes` 的模式:滚动一屏 → 重新 `colorRows()` → 合并新行 → 直到稳定边界或次数上限。 6. `rowCount` 改为每轮重新计算,不再于第一帧冻结;已处理行以行内容签名而非索引标识,避免滚动后索引错位。 7. `swipeSpec` 横向分支增加兜底:取不到 `width > height` 的可滚动祖先时,不直接退回全局兜底,而是判定该维度为纵向布局并跳过横向翻页,避免无效手势与误滑。 8. 自动布局判定:按颜色节点 bounds 的行列分布判断单行、多行网格或单列,作为默认行为。 ### 3. 分支 B · 规格值判定(确认后实施) 9. 修正 `parse` 中 spec value 的接受条件:允许「自身不可点击但存在可点击祖先」或「带明确选中语义」的节点作为规格值,并在结果中如实标记 `available`。 10. 严禁放宽为「按位置猜测同容器内的兄弟节点」;无标题归属或无可点击路径的节点仍不得作为规格值。 11. 若确认为分支 B,需同时确认这些值能否被安全点击;不能点击时按现有不完整契约提交 `completed_partial`,并在缺失项如实标注。 ### 4. 重排导致的提前退出 12. `:905-913` 的 `rowIndex >= rows.size` 分支不再直接 break:重新扫描当前所有行,对照 `attempted` 判断是否仍有未尝试且可用的值;确无剩余时才结束,并记录 `COLOR_ROW_REFLOWED`。 ### 5. 规则参数 13. 采集规则 `limits` 新增 `colorVerticalSwipes`(颜色纵向发现次数上限),沿用既有边界校验口径;未提供时取 `specVerticalSwipes` 作为默认值,保证存量规则快照不失效。 14. `collector` 新增可选 `colorLayout: auto | horizontal | vertical | grid`,**默认 `auto`**,仅作为自动判定失灵时的临时覆盖手段。 15. 服务端 `rulecontract` 同步新增校验,字段名与上下限与 Android 解析保持一致。 > 说明:布局不适合以规则为主力手段。当前采集规则是全局的(`AgentManualCollectionSetting` 指向单条规则,所有当前页面采集任务共用),而布局逐商品不同;把 `colorLayout` 写死会顾此失彼。因此以自动判定为主、规则覆盖为辅。 ## 安全边界 - 不点击相近候选、不猜测规格、不按坐标盲点;服务端仍是规格匹配的裁决方。 - 不点击下单、支付、地址及其可点击祖先;Agent 侧不可配置的拒绝清单保持不变。 - 诊断不记录颜色文案、价格、链接、goods_id、剪贴板、控件树与截图。 - 不使用 OCR/VLM。 - 不涉及创建订单、权限、并发、服务端迁移与删除数据;唯一迁移是已授权的 Agent 本地诊断库 v1 → v2 可空列增量迁移。 ## 验收标准 **诊断(可独立验收)** - [ ] 一次真机采集后,本地诊断包含 `COLOR_DISCOVERY` 记录,可读出行数、每行值数、可点击值数、不可点击候选数、滚动次数与终止原因。 - [ ] 诊断内容不含颜色文案、价格与任何原始结构数据。 - [ ] 人为模拟诊断写入失败时,采集结果不变。 **分支 A(若确认)** - [ ] 纵向或网格排列的商品,能发现初始视口之外的颜色行,采到的颜色数与面板实际可见颜色数一致。 - [ ] 横排商品行为不回退,颜色数与修复前一致。 - [ ] 达到稳定边界或次数上限时正常结束,不无限滚动。 **分支 B(若确认)** - [ ] 未选中颜色项被正确解析为规格值并如实标记 `available`。 - [ ] 无可点击路径的值不被点击,按不完整契约提交并在缺失项标注。 **共同** - [ ] PDD 重排导致行消失时不再直接结束,仍能继续处理剩余未尝试的值。 - [ ] 未提供新 `limits` / `colorLayout` 的存量规则快照行为不变。 - [ ] 尺码遍历(#111)、面板证据(#112)、订单确认回顶(#113)不回退。 ## 验证方式 - `cd android && .\gradlew.bat :app:testDebugUnitTest :app:assembleDebug` - 颜色遍历与布局判定的纯函数单元测试:单行横排、多行网格、单列纵向、重排后行消失四种输入。 - `go test ./app/goauto/rulecontract/...` - 真机 PKG110:分别用一个横排多色商品与一个纵向/网格多色商品各采集一次,记录 Agent 版本、规则 ID/快照、任务号、采到的颜色数与面板实际颜色数。 - 真机、多设备、其他 ROM 与异常路径未覆盖部分如实回写。 ## 依赖、并行与风险 - 前置依赖:#115(`e117fd2`)、#116(`3619435`)已合并;#112、#113 已合并。 - 不建议与其他修改 `PddProductDetailCollector` 或 `GoAutoAccessibilityService` 手势逻辑的工单并行。 - 风险:纵向发现循环若终止条件不当会拉长采集时间。缓解:沿用 `stableEdgeReads` 稳定边界与次数上限,并受规则总超时约束。 - 风险:分支 B 的判定放宽有引入误识别的可能。缓解:只接受有可点击祖先或明确选中语义的节点,不按位置猜测。 - 回退:还原本工单 Android 提交即可;新增规则字段为可选,存量快照不受影响。 ## 文档影响 - 需更新 Wiki `Android-Agent-API-Contract`(`docs/08-agent-api-contract.md`):采集规则新增 `limits.colorVerticalSwipes` 与 `collector.colorLayout` 的说明与默认值。 - `Business-Rules-and-Glossary`(`docs/03-business-rules-and-glossary.md`):如颜色完整性判定口径发生变化则同步更新;仅补充发现能力时可记为无长期文档影响并说明原因。 - 按 Wiki-first 门禁:先改线上页面并回读 revision,再执行一轮 `sync` 与一轮 `sync --check`,把页面与 revision 写回本工单。 ## 状态 第 1 项诊断修订已由提交 `d718c95` 完成,等待 Debug APK 真机读取验收;第 2~5 项未实施。取得原问题商品的脱敏聚合证据并由用户确认分支前,不继续修改遍历、解析或手势逻辑。
Author
Owner

补充:参考实现分析与第三个待证实分支

用户提示 /mnt/d/chengma/cmautobuy/client 已有处理同类问题的 Python 实现。已只读分析 client/src/pdd_collect_service.py(2819 行,当前工作树,未做提交基线核对,仅作行为参考)。结论如下。

一、参考实现同样没有颜色纵向发现(重要,防止照抄)

_collect_color_prices(:1631)与 GoAuto 的 collectColors 结构基本一致:

first_rows = self._visible_color_rows(first_xml)
row_count = len(first_rows)          # 同样在第一帧冻结
for row_index in range(row_count):
    move_right = row_index % 2 == 0  # 同样只有横向蛇形遍历

纵向滚动只出现在 _clear_default_size_selection(:1866)与 _move_spec_panel_to_top(:1928),颜色遍历中没有任何纵向动作。

因此:若确认为分支 A(纵向布局),参考实现不提供可借鉴方案,该部分必须原创;实施时不得以「参考项目如此实现」为由跳过纵向发现能力。

二、可直接借鉴的四个机制

  1. 行消失时明确失败,不静默(:1671):

    if row_index >= len(rows):
        raise PddCollectError("PDD_DATA_SPEC_INCOMPLETE", f"颜色第 {row_index + 1} 行在滑动后消失")
    

    GoAuto 在对应位置(PddProductDetailCollector.kt:905-913)是静默 break,导致本次「任务成功但只有一个颜色」的无声失败。本工单第 4 项(重排提前退出)应至少保证该情况可被诊断区分;是否升级为失败按实施时的证据决定,不得继续无声吞掉。

  2. 滑动区域选法更可靠(_horizontal_region :2773):选取最深的可滚动节点,且要求其子节点含 clickable,不依赖宽高比。GoAuto 的 GoAutoAccessibilityService.kt:365-368 按 width > height 筛选,在纵向或嵌套容器下直接失效。本工单第 7 项改为采用这一选法,优先级高于原文的「判定为纵向布局并跳过横向翻页」。

  3. 截断项过滤(_visible_color_rows :2650):

    widest = max(item.bounds[2] - item.bounds[0] for item in candidates)
    minimum_width = max(48, int(widest * 0.6))
    

    过滤被屏幕边缘截断的半个按钮;自绘非滚动面板(按钮宽度随文字长度变化)时则保留全部候选,不做宽度过滤。GoAuto 的 colorRows(:1306-1323)没有这层,可能把截断项当成完整值。

  4. 滑动后等待视口真实变化(_wait_for_horizontal_change):GoAuto 目前是固定 pause(350),慢设备上可能读到旧视口。

三、新增待证实分支 C · 默认选中态干扰

参考实现有一个 GoAuto 完全没有的前置步骤 _clear_default_size_selection(:1866):进入规格面板后,先定位默认已选中的尺码并取消选择(且只在唯一选中项明确时点击一次,页面不支持取消时不重复点击),随后 _move_spec_panel_to_top 回顶,再开始逐色采价。

该步骤的存在说明参考项目遇到过「默认选中态干扰规格遍历」的真实问题。本次任务结果为「白色 + 均码」两个维度各仅一个值,与该情形吻合:若进入面板时带默认选中态,部分颜色可能因当前选中尺码无货而不出现在可点击节点中,从而在解析阶段就只产出一个 color 值。

补充佐证:参考实现的 _top_level_clickable_options(:796)同样要求 clickable == "true",即原工单的分支 B(未选中项不可点击)在参考实现中同样会失败。这反过来提高了分支 C 的分量。

因此待证实分支由两个扩展为三个:

  • 分支 A · 纵向布局未覆盖 → 修复重点在遍历(需原创)
  • 分支 B · 未选中项未被解析为规格值 → 修复重点在 parse 判定条件
  • 分支 C · 默认选中态干扰 → 修复重点在进入面板后的前置清除步骤,可借鉴 _clear_default_size_selection 的安全约束(唯一选中项才点、只点一次、取消失败不重试)

四、对应的诊断字段调整

原方案第 1 项的诊断需增加一个字段:进入规格面板时已处于选中状态的维度值数量(按维度分别计数)。加上原有的「不可点击但可见的候选数量」,一次真机记录即可三选一:

诊断读数 分支
不可点击候选数 ≈ 0,已选中数 ≥ 1,可点击颜色值 = 1 C
不可点击候选数显著 > 可点击值数 B
两者都不显著,且纵向滚动后出现新行 A

诊断仍不得记录颜色文案、价格、控件树、坐标原文与截图。

五、参考边界

  • 只借鉴上述行为设计,不引入 uiautomator2、原始控件 XML dump 与截图诊断方式。
  • 参考文件存在本地未提交改动,本评论只将其当前工作树作为行为参考,不声明为某一提交的纯净实现。
  • 参考项目为独立代码库,不复制其源码,按 GoAuto 的无障碍节点模型重新实现。

六、正文其余部分

目标、非目标、安全边界、验证方式、依赖与文档影响不变。实施顺序仍为:先落地诊断 → 取得一次真机记录 → 确认分支 → 实施对应修复。

## 补充:参考实现分析与第三个待证实分支 用户提示 `/mnt/d/chengma/cmautobuy/client` 已有处理同类问题的 Python 实现。已只读分析 `client/src/pdd_collect_service.py`(2819 行,当前工作树,未做提交基线核对,仅作行为参考)。结论如下。 ### 一、参考实现同样没有颜色纵向发现(重要,防止照抄) `_collect_color_prices`(`:1631`)与 GoAuto 的 `collectColors` 结构基本一致: ```python first_rows = self._visible_color_rows(first_xml) row_count = len(first_rows) # 同样在第一帧冻结 for row_index in range(row_count): move_right = row_index % 2 == 0 # 同样只有横向蛇形遍历 ``` 纵向滚动只出现在 `_clear_default_size_selection`(`:1866`)与 `_move_spec_panel_to_top`(`:1928`),颜色遍历中没有任何纵向动作。 **因此:若确认为分支 A(纵向布局),参考实现不提供可借鉴方案,该部分必须原创;实施时不得以「参考项目如此实现」为由跳过纵向发现能力。** ### 二、可直接借鉴的四个机制 1. **行消失时明确失败,不静默**(`:1671`): ```python if row_index >= len(rows): raise PddCollectError("PDD_DATA_SPEC_INCOMPLETE", f"颜色第 {row_index + 1} 行在滑动后消失") ``` GoAuto 在对应位置(`PddProductDetailCollector.kt:905-913`)是静默 `break`,导致本次「任务成功但只有一个颜色」的无声失败。本工单第 4 项(重排提前退出)应至少保证该情况可被诊断区分;是否升级为失败按实施时的证据决定,不得继续无声吞掉。 2. **滑动区域选法更可靠**(`_horizontal_region` `:2773`):选取**最深的可滚动节点,且要求其子节点含 clickable**,不依赖宽高比。GoAuto 的 `GoAutoAccessibilityService.kt:365-368` 按 `width > height` 筛选,在纵向或嵌套容器下直接失效。**本工单第 7 项改为采用这一选法**,优先级高于原文的「判定为纵向布局并跳过横向翻页」。 3. **截断项过滤**(`_visible_color_rows` `:2650`): ```python widest = max(item.bounds[2] - item.bounds[0] for item in candidates) minimum_width = max(48, int(widest * 0.6)) ``` 过滤被屏幕边缘截断的半个按钮;自绘非滚动面板(按钮宽度随文字长度变化)时则保留全部候选,不做宽度过滤。GoAuto 的 `colorRows`(`:1306-1323`)没有这层,可能把截断项当成完整值。 4. **滑动后等待视口真实变化**(`_wait_for_horizontal_change`):GoAuto 目前是固定 `pause(350)`,慢设备上可能读到旧视口。 ### 三、新增待证实分支 C · 默认选中态干扰 参考实现有一个 GoAuto 完全没有的前置步骤 `_clear_default_size_selection`(`:1866`):进入规格面板后,先定位默认已选中的尺码并取消选择(且只在唯一选中项明确时点击一次,页面不支持取消时不重复点击),随后 `_move_spec_panel_to_top` 回顶,再开始逐色采价。 该步骤的存在说明参考项目遇到过「默认选中态干扰规格遍历」的真实问题。本次任务结果为「白色 + 均码」两个维度各仅一个值,与该情形吻合:若进入面板时带默认选中态,部分颜色可能因当前选中尺码无货而不出现在可点击节点中,从而在解析阶段就只产出一个 color 值。 补充佐证:参考实现的 `_top_level_clickable_options`(`:796`)同样要求 `clickable == "true"`,即原工单的分支 B(未选中项不可点击)在参考实现中同样会失败。这反过来提高了分支 C 的分量。 **因此待证实分支由两个扩展为三个:** - 分支 A · 纵向布局未覆盖 → 修复重点在遍历(需原创) - 分支 B · 未选中项未被解析为规格值 → 修复重点在 `parse` 判定条件 - **分支 C · 默认选中态干扰** → 修复重点在进入面板后的前置清除步骤,可借鉴 `_clear_default_size_selection` 的安全约束(唯一选中项才点、只点一次、取消失败不重试) ### 四、对应的诊断字段调整 原方案第 1 项的诊断需增加一个字段:**进入规格面板时已处于选中状态的维度值数量(按维度分别计数)**。加上原有的「不可点击但可见的候选数量」,一次真机记录即可三选一: | 诊断读数 | 分支 | |---|---| | 不可点击候选数 ≈ 0,已选中数 ≥ 1,可点击颜色值 = 1 | C | | 不可点击候选数显著 > 可点击值数 | B | | 两者都不显著,且纵向滚动后出现新行 | A | 诊断仍不得记录颜色文案、价格、控件树、坐标原文与截图。 ### 五、参考边界 - 只借鉴上述行为设计,不引入 uiautomator2、原始控件 XML dump 与截图诊断方式。 - 参考文件存在本地未提交改动,本评论只将其当前工作树作为行为参考,不声明为某一提交的纯净实现。 - 参考项目为独立代码库,不复制其源码,按 GoAuto 的无障碍节点模型重新实现。 ### 六、正文其余部分 目标、非目标、安全边界、验证方式、依赖与文档影响不变。实施顺序仍为:先落地诊断 → 取得一次真机记录 → 确认分支 → 实施对应修复。
Author
Owner

开始实施第 1 项「颜色阶段诊断」。本次范围按用户明确指令收窄:仅新增脱敏、旁路保护的颜色诊断及测试;不修改 collectColors 的遍历逻辑,不修改 PddScreenParser.parse 判定条件,不修改 swipeSpec。完成后提交并停在待验收,不实施工单第 2~5 项。

开始实施第 1 项「颜色阶段诊断」。本次范围按用户明确指令收窄:仅新增脱敏、旁路保护的颜色诊断及测试;不修改 `collectColors` 的遍历逻辑,不修改 `PddScreenParser.parse` 判定条件,不修改 `swipeSpec`。完成后提交并停在待验收,不实施工单第 2~5 项。
Author
Owner

第 1 项已实施,等待验收

已按用户明确收窄的范围完成颜色阶段诊断,未实施第 2~5 项。

实现

  • Agent 版本:0.9.12(versionCode 25)。
  • 新增诊断阶段:COLOR_DISCOVERY。
  • 使用既有 agent_diagnostic 表和通用数值字段记录脱敏聚合事件,没有新增数据库列或迁移:
    • 每行发现值数量;
    • 解析到的颜色值总数;
    • 可见但不可点击候选数;
    • 选中值数量;
    • 横向、纵向发现滑动次数(当前遍历逻辑下纵向为 0);
    • 稳定边界、扫描上限、行重排、滑动失败、容器不可用等终止原因;
    • 阶段耗时。
  • 诊断不保存颜色文案、价格、坐标、控件树、XML、截图、链接或 goods_id。
  • 继续经 SafeAgentDiagnosticRecorder 旁路写入;诊断持久化失败不会改变采集结果。
  • 未修改共享 API、规则契约或数据库结构。

明确未修改

  • 未改变 collectColors 的固定首帧行数、横向蛇形遍历、滚动上限或采集结果逻辑;仅在原有分支旁增加观察与终止原因记录。
  • 未修改 PddScreenParser.parse 的规格值判定条件。
  • 未修改 GoAutoAccessibilityService.swipeSpec。
  • 未实现纵向/网格颜色发现、默认尺码取消、节点判定放宽或重排修复。

验证

  • python dev_scripts/harness.py check --strict:通过。
  • .\scripts\verify.ps1 -Component android:Debug/Release 单元测试通过,Debug APK 构建通过。
  • 新增回归覆盖:
    • 行数量、聚合候选、选中状态、横/纵滑动次数与终止原因;
    • 持久化内容不含颜色文案、价格或不可点击候选原文;
    • 模拟诊断数据库写入失败时,采集仍成功且结果不变。
  • APK:android/app/build/outputs/apk/debug/app-debug.apk。

提交

  • 9bb19b4d0f80e753c03689b5853128ad968b07b6 — feat(#124): add color discovery diagnostics
  • 已推送至 origin/main。

文档影响与未验证项

本阶段只增加 Agent 内部脱敏诊断枚举和落库事件,未改变业务规则、共享接口、配置、状态或操作方式,判定为无长期 Wiki 文档影响,按规则跳过 Wiki 更新与同步。

尚未执行 PKG110 真机采集;需要安装 0.9.12 后运行一次原问题商品,读取 COLOR_DISCOVERY 聚合记录,再决定 #124 后续应进入纵向布局、解析判定或其他分支。本工单保持打开,状态为待验收。

## 第 1 项已实施,等待验收 已按用户明确收窄的范围完成颜色阶段诊断,未实施第 2~5 项。 ### 实现 - Agent 版本:`0.9.12`(versionCode 25)。 - 新增诊断阶段:`COLOR_DISCOVERY`。 - 使用既有 `agent_diagnostic` 表和通用数值字段记录脱敏聚合事件,没有新增数据库列或迁移: - 每行发现值数量; - 解析到的颜色值总数; - 可见但不可点击候选数; - 选中值数量; - 横向、纵向发现滑动次数(当前遍历逻辑下纵向为 0); - 稳定边界、扫描上限、行重排、滑动失败、容器不可用等终止原因; - 阶段耗时。 - 诊断不保存颜色文案、价格、坐标、控件树、XML、截图、链接或 goods_id。 - 继续经 `SafeAgentDiagnosticRecorder` 旁路写入;诊断持久化失败不会改变采集结果。 - 未修改共享 API、规则契约或数据库结构。 ### 明确未修改 - 未改变 `collectColors` 的固定首帧行数、横向蛇形遍历、滚动上限或采集结果逻辑;仅在原有分支旁增加观察与终止原因记录。 - 未修改 `PddScreenParser.parse` 的规格值判定条件。 - 未修改 `GoAutoAccessibilityService.swipeSpec`。 - 未实现纵向/网格颜色发现、默认尺码取消、节点判定放宽或重排修复。 ### 验证 - `python dev_scripts/harness.py check --strict`:通过。 - `.\scripts\verify.ps1 -Component android`:Debug/Release 单元测试通过,Debug APK 构建通过。 - 新增回归覆盖: - 行数量、聚合候选、选中状态、横/纵滑动次数与终止原因; - 持久化内容不含颜色文案、价格或不可点击候选原文; - 模拟诊断数据库写入失败时,采集仍成功且结果不变。 - APK:`android/app/build/outputs/apk/debug/app-debug.apk`。 ### 提交 - `9bb19b4d0f80e753c03689b5853128ad968b07b6` — `feat(#124): add color discovery diagnostics` - 已推送至 `origin/main`。 ### 文档影响与未验证项 本阶段只增加 Agent 内部脱敏诊断枚举和落库事件,未改变业务规则、共享接口、配置、状态或操作方式,判定为无长期 Wiki 文档影响,按规则跳过 Wiki 更新与同步。 尚未执行 PKG110 真机采集;需要安装 0.9.12 后运行一次原问题商品,读取 `COLOR_DISCOVERY` 聚合记录,再决定 #124 后续应进入纵向布局、解析判定或其他分支。本工单保持打开,状态为待验收。
Author
Owner

第 1 项(颜色阶段诊断)评审 — 提交 9bb19b4

范围遵守良好:未改动 collectColors 的遍历算法、parse 判定条件与 swipeSpec,符合「只做诊断」的约束。终止原因分支覆盖完整(reflow / edge / limit / swipe failed / container unavailable),并补充了单元测试。

但建议改完下列第 1、2、4 点再装机验收,否则本次真机很可能给出误导性读数。

必须改

1. 已选中判定口径过窄,会把分支 C 误排除

当前实现:

diagnosticSelectedValues = maxOf(
    diagnosticSelectedValues,
    values.count { it.node.selected || it.node.checked },
)

只检查规格值节点自身的 selected / checked。PDD 大量自绘控件把选中态放在后代节点上,父节点两个标志均为 false。

参考实现对照(/mnt/d/chengma/cmautobuy/client/src/pdd_collect_service.py):

  • _node_is_selected(:2688)遍历自身及全部后代:
    return any(item.get("selected") == "true" or item.get("checked") == "true" for item in node.iter())
    
  • _color_selection_state_exposed(:2694)把已选摘要 snapshot.selected_text 作为首选证据,节点标志只作兜底。

GoAuto 的 ParsedPddScreen 已有现成的 selectedSummary 字段,本次未使用。

要求:选中判定改为遍历节点自身及后代;同时把 selectedSummary 是否非空(以及其中可识别的维度值数量)一并记入诊断。按当前写法,若 PDD 不暴露 selected,该字段将恒为 0,从而错误地排除分支 C —— 而分支 C 正是与本次「白色 + 均码」现象最吻合的假设。

2. 单次采集写入 8~10 条诊断,会挤掉其它阶段历史

recordColorDiscovery 把每个度量写成一条独立记录:每行一条 COLOR_ROW_VALUE_COUNT,加 5 条固定度量,再加终止原因。

而 AgentDiagnosticStore.kt:104 的 MAX_RECORDS = 50 是全局上限,按 id 倒序保留(:172)。一次当前页面采集本就要写 LINK_RESOLUTION、DETAIL_ENTRY、SPEC_PANEL_ENTRY、SIZE_DISCOVERY,颜色阶段再吃掉近 10 条,跑三四次即会把此前各阶段记录全部冲掉,后续跨阶段排查将失去证据。

要求:一次颜色采集只写 1 条记录;各项度量改为 AgentDiagnosticEvent 的独立数值字段(参照既有 clipboardPollCount / clipboardItemCount / clipboardContentLength 的做法新增列),不得塞进 reason 枚举。每行值数量可用一个「行数 + 各行值数的紧凑摘要」单字段承载,仍不含任何文案。

应该改

3. COLOR_FOUND 同时充当度量键与终止原因,读数有歧义

record(AgentDiagnosticReason.COLOR_FOUND, count = parsedValueCount)   // 作度量
if (reason != AgentDiagnosticReason.COLOR_FOUND) record(reason, ...)  // 又作终止原因

读取时无法区分某条记录表示「终止原因为正常完成」还是「解析值总数」。按第 2 点合并为单条记录后该问题自然消除。

同时,COLOR_ROW_VALUE_COUNT、COLOR_SELECTED_VALUE_COUNT、COLOR_HORIZONTAL_SWIPE_COUNT、COLOR_VERTICAL_SWIPE_COUNT 属于数据而非原因,不应出现在 AgentDiagnosticReason 中,随第 2 点一并移除。其中 COLOR_VERTICAL_SWIPE_COUNT 当前恒写 0,属占位,本阶段可直接删除,待第 2 项(纵向发现)实施时再引入。

4. 缺少尺码维度的选中数

原方案要求「颜色/尺码分开计」,当前仅统计 color 维度。分支 C 的典型形态是默认选中的尺码过滤掉了部分颜色的可用性——参考实现的前置步骤即名为 _clear_default_size_selection(:1866)。只统计颜色选中数会漏掉最关键的一半证据。

要求:颜色与尺码的已选中值数量分别记录。

做得好的部分

  • visibleNonClickableColorCandidateCount 的区间圈定合理:以颜色标题 bounds.bottom 为上界、下一个维度标题 bounds.top 为下界,并排除含后代的容器节点避免重复计数,字段质量满足分支判定需要。
  • 严格遵守了范围约束,未提前动遍历与解析逻辑。
  • 诊断内容不含颜色文案、价格与原始结构数据,符合安全边界。

验收口径

改完第 1、2、4 点后装机,对同一商品采集一次,goauto_diagnostics.db 中应有一条 COLOR_DISCOVERY 记录,可读出:解析出的可点击颜色值数、可见但不可点击的候选数、颜色已选中数、尺码已选中数、已选摘要是否非空、行数与各行值数、横向滑动次数、终止原因。本阶段不要求采集结果变好。

## 第 1 项(颜色阶段诊断)评审 — 提交 `9bb19b4` 范围遵守良好:未改动 `collectColors` 的遍历算法、`parse` 判定条件与 `swipeSpec`,符合「只做诊断」的约束。终止原因分支覆盖完整(reflow / edge / limit / swipe failed / container unavailable),并补充了单元测试。 **但建议改完下列第 1、2、4 点再装机验收**,否则本次真机很可能给出误导性读数。 ### 必须改 #### 1. 已选中判定口径过窄,会把分支 C 误排除 当前实现: ```kotlin diagnosticSelectedValues = maxOf( diagnosticSelectedValues, values.count { it.node.selected || it.node.checked }, ) ``` 只检查规格值节点**自身**的 `selected` / `checked`。PDD 大量自绘控件把选中态放在后代节点上,父节点两个标志均为 false。 参考实现对照(`/mnt/d/chengma/cmautobuy/client/src/pdd_collect_service.py`): - `_node_is_selected`(`:2688`)遍历**自身及全部后代**: ```python return any(item.get("selected") == "true" or item.get("checked") == "true" for item in node.iter()) ``` - `_color_selection_state_exposed`(`:2694`)把**已选摘要 `snapshot.selected_text` 作为首选证据**,节点标志只作兜底。 GoAuto 的 `ParsedPddScreen` 已有现成的 `selectedSummary` 字段,本次未使用。 **要求**:选中判定改为遍历节点自身及后代;同时把 `selectedSummary` 是否非空(以及其中可识别的维度值数量)一并记入诊断。按当前写法,若 PDD 不暴露 `selected`,该字段将恒为 0,从而错误地排除分支 C —— 而分支 C 正是与本次「白色 + 均码」现象最吻合的假设。 #### 2. 单次采集写入 8~10 条诊断,会挤掉其它阶段历史 `recordColorDiscovery` 把每个度量写成一条独立记录:每行一条 `COLOR_ROW_VALUE_COUNT`,加 5 条固定度量,再加终止原因。 而 `AgentDiagnosticStore.kt:104` 的 `MAX_RECORDS = 50` 是**全局上限**,按 id 倒序保留(`:172`)。一次当前页面采集本就要写 `LINK_RESOLUTION`、`DETAIL_ENTRY`、`SPEC_PANEL_ENTRY`、`SIZE_DISCOVERY`,颜色阶段再吃掉近 10 条,跑三四次即会把此前各阶段记录全部冲掉,后续跨阶段排查将失去证据。 **要求**:一次颜色采集只写 **1 条**记录;各项度量改为 `AgentDiagnosticEvent` 的独立数值字段(参照既有 `clipboardPollCount` / `clipboardItemCount` / `clipboardContentLength` 的做法新增列),不得塞进 `reason` 枚举。每行值数量可用一个「行数 + 各行值数的紧凑摘要」单字段承载,仍不含任何文案。 ### 应该改 #### 3. `COLOR_FOUND` 同时充当度量键与终止原因,读数有歧义 ```kotlin record(AgentDiagnosticReason.COLOR_FOUND, count = parsedValueCount) // 作度量 if (reason != AgentDiagnosticReason.COLOR_FOUND) record(reason, ...) // 又作终止原因 ``` 读取时无法区分某条记录表示「终止原因为正常完成」还是「解析值总数」。按第 2 点合并为单条记录后该问题自然消除。 同时,`COLOR_ROW_VALUE_COUNT`、`COLOR_SELECTED_VALUE_COUNT`、`COLOR_HORIZONTAL_SWIPE_COUNT`、`COLOR_VERTICAL_SWIPE_COUNT` 属于**数据而非原因**,不应出现在 `AgentDiagnosticReason` 中,随第 2 点一并移除。其中 `COLOR_VERTICAL_SWIPE_COUNT` 当前恒写 0,属占位,本阶段可直接删除,待第 2 项(纵向发现)实施时再引入。 #### 4. 缺少尺码维度的选中数 原方案要求「颜色/尺码分开计」,当前仅统计 `color` 维度。分支 C 的典型形态是**默认选中的尺码**过滤掉了部分颜色的可用性——参考实现的前置步骤即名为 `_clear_default_size_selection`(`:1866`)。只统计颜色选中数会漏掉最关键的一半证据。 **要求**:颜色与尺码的已选中值数量分别记录。 ### 做得好的部分 - `visibleNonClickableColorCandidateCount` 的区间圈定合理:以颜色标题 `bounds.bottom` 为上界、下一个维度标题 `bounds.top` 为下界,并排除含后代的容器节点避免重复计数,字段质量满足分支判定需要。 - 严格遵守了范围约束,未提前动遍历与解析逻辑。 - 诊断内容不含颜色文案、价格与原始结构数据,符合安全边界。 ### 验收口径 改完第 1、2、4 点后装机,对同一商品采集一次,`goauto_diagnostics.db` 中应有**一条** `COLOR_DISCOVERY` 记录,可读出:解析出的可点击颜色值数、可见但不可点击的候选数、颜色已选中数、尺码已选中数、已选摘要是否非空、行数与各行值数、横向滑动次数、终止原因。本阶段不要求采集结果变好。
Author
Owner

第 1 项评审修订(全栈复核结论)

对评论 #5174 与提交 9bb19b4 复核后,确认“单次颜色阶段只写一条诊断”和“分别记录颜色/尺码初始选中数”的方向正确,但第 1 点部分代码判断不成立,且新增字段涉及本地数据库迁移。后续不得直接按 #5174 原文实施,应以本评论为准修订。

一、纠正选中态判断

#5174 所述“当前实现只检查规格节点自身,未检查后代节点”不成立。

PddScreenParser.parse 在构造规范化节点时已经执行:

selected = node.selected || descendants.any(SnapshotNode::selected)
checked = node.checked || descendants.any(SnapshotNode::checked)

因此 VisibleSpecValue.node.selected/checked 已包含后代节点状态,不需要在诊断层重复遍历后代。

当前实现的真实问题是:diagnosticSelectedValues 对整个颜色采集过程取最大值。Agent 自己点击颜色后,后续快照可能产生选中态,从而污染“进入面板时是否已默认选中”的证据。

修订要求:

  1. 初始选中态只从首次颜色点击之前的诊断快照读取,不得与后续 Agent 点击产生的状态合并。
  2. 分别记录:
    • 初始已选颜色值数量;
    • 初始已选尺码值数量。
  3. selectedSummary != null 不能直接作为已选证据,因为 selectedSummary 也可能匹配“请选择”。只有摘要按规则中的 selection.selectedPrefixes(如“已选/已選”)开头时,才记录“存在已选摘要”。
  4. 只记录布尔值或数量,不保存摘要原文和规格值原文。

二、单条诊断记录方向确认

AgentDiagnosticStore 当前全局最多保留 50 条记录。一次颜色阶段写入多条度量事件会过快淘汰详情进入、规格面板、尺码发现等其他阶段证据,因此后续应调整为:

  • 一次 collectColors 最多写入 1 条 COLOR_DISCOVERY;
  • reason 只表示最终终止原因;
  • 数量类数据必须进入独立字段,不再使用原因枚举承载。

应删除以下“指标型原因”:

  • COLOR_ROW_VALUE_COUNT
  • COLOR_SELECTED_VALUE_COUNT
  • COLOR_HORIZONTAL_SWIPE_COUNT
  • COLOR_VERTICAL_SWIPE_COUNT

COLOR_FOUND 不再同时充当数量指标。正常结束时由实际终止原因表达,例如稳定边界为 COLOR_EDGE_REACHED、达到上限为 COLOR_SCAN_LIMIT。

三、建议的单记录字段

单条 COLOR_DISCOVERY 建议包含以下脱敏字段:

  • row_count:识别到的颜色行数;
  • row_value_counts:各行值数量的紧凑摘要,只允许数字和分隔符,并限制长度;
  • clickable_color_count:解析到的可点击颜色值数量;
  • non_clickable_candidate_count:颜色区间内可见但未解析为可点击规格值的候选数量;
  • initial_selected_color_count:首次颜色点击前已选颜色值数量;
  • initial_selected_size_count:首次颜色点击前已选尺码值数量;
  • selected_summary_present:是否存在以 selection.selectedPrefixes 开头的已选摘要;
  • horizontal_swipe_count:颜色发现阶段实际成功的横向滑动次数;
  • 复用既有 elapsed_ms;
  • 复用 reason 保存唯一终止原因。

本阶段没有颜色纵向发现,vertical_swipe_count 恒为 0,没有诊断价值,应暂不新增;待纵向发现分支正式实施时再加入。

继续禁止保存颜色/尺码文案、价格、摘要原文、坐标、链接、goods_id、控件树、XML 和截图。

四、数据库迁移门禁

上述独立字段需要修改 Agent 本地 SQLite agent_diagnostic 表,这与工单正文现有“不修改数据库结构”描述冲突,也属于项目规则要求人工确认的数据库迁移。

因此后续实施前必须:

  1. 先修订 #124 的范围、非目标、风险与回退说明,明确仅新增本地诊断表的可空字段,不涉及服务端数据库;
  2. 获得用户对本地 SQLite 增量迁移的明确确认;
  3. DATABASE_VERSION 从 1 升级到 2;
  4. 实现并测试 v1 → v2 的非破坏性 ALTER TABLE ADD COLUMN 迁移;
  5. 保留已有诊断记录,不删除、不重建表;
  6. 不得复用或曲解 clipboard* / target* / candidateCount / attempt 等旧字段来塞入颜色指标。

在取得迁移确认前,不继续修改代码。

五、诊断能力边界

本阶段明确不执行颜色纵向滑动,因此单次诊断不能独立证明“纵向滑动后出现新行”,也不能保证一次记录完成 A/B/C 三选一。

诊断只能:

  • 通过不可点击候选数为分支 B 提供支持证据;
  • 通过首次点击前的尺码/颜色选中数及已选摘要为分支 C 提供支持证据;
  • 当 B/C 均无明显证据时,结合手机界面人工观察,进一步验证分支 A。

这些读数是诊断证据,不是充分因果证明,不得据此自动执行取消尺码、放宽解析或纵向滚动修复。

六、真机读取与验收补充

当前诊断只保存在 Agent 本地数据库,没有 Admin/API 查看入口。装机验收前必须在工单写明可复现的读取路径:

  • 使用 Debug APK;
  • 明确 adb shell run-as <最终包名> 读取或导出 goauto_diagnostics.db 的具体命令;
  • 验证同一任务只产生一条 COLOR_DISCOVERY;
  • 记录设备、Agent 0.9.12(或修订后的新版本)、任务号和规则快照;
  • 不把数据库文件、规格文案或其他任务原始数据上传工单,只回写脱敏聚合读数。

若正式 APK 不允许 run-as,则本工单必须另行确认安全的只读诊断出口;不能只声称“已落库”后直接验收。

七、修订后的测试要求

  • 一次颜色采集只产生一条 COLOR_DISCOVERY。
  • 首次点击前颜色、尺码选中数分别正确,后续 Agent 点击不改变初始读数。
  • 后代节点暴露的 selected/checked 继续通过现有 Parser 规范化结果生效。
  • “请选择”不记为已选摘要,“已选”才记为已选摘要。
  • v1 → v2 迁移保留旧记录并补齐可空列。
  • 诊断内容不包含任何规格文案、价格与原始页面结构。
  • 模拟诊断写入失败时采集行为和结果不变。
  • collectColors 遍历、PddScreenParser.parse 判定条件和 swipeSpec 仍不得改变。

状态

提交 9bb19b4 已完成首版诊断,但按本评论发现的问题,暂不进入真机验收。下一步应先由用户确认是否允许 Agent 本地 SQLite v1 → v2 增量迁移;确认后仅修订第 1 项诊断,不实施 #124 第 2~5 项。

## 第 1 项评审修订(全栈复核结论) 对评论 #5174 与提交 `9bb19b4` 复核后,确认“单次颜色阶段只写一条诊断”和“分别记录颜色/尺码初始选中数”的方向正确,但第 1 点部分代码判断不成立,且新增字段涉及本地数据库迁移。后续不得直接按 #5174 原文实施,应以本评论为准修订。 ### 一、纠正选中态判断 #5174 所述“当前实现只检查规格节点自身,未检查后代节点”不成立。 `PddScreenParser.parse` 在构造规范化节点时已经执行: ```kotlin selected = node.selected || descendants.any(SnapshotNode::selected) checked = node.checked || descendants.any(SnapshotNode::checked) ``` 因此 `VisibleSpecValue.node.selected/checked` 已包含后代节点状态,不需要在诊断层重复遍历后代。 当前实现的真实问题是:`diagnosticSelectedValues` 对整个颜色采集过程取最大值。Agent 自己点击颜色后,后续快照可能产生选中态,从而污染“进入面板时是否已默认选中”的证据。 **修订要求:** 1. 初始选中态只从首次颜色点击之前的诊断快照读取,不得与后续 Agent 点击产生的状态合并。 2. 分别记录: - 初始已选颜色值数量; - 初始已选尺码值数量。 3. `selectedSummary != null` 不能直接作为已选证据,因为 `selectedSummary` 也可能匹配“请选择”。只有摘要按规则中的 `selection.selectedPrefixes`(如“已选/已選”)开头时,才记录“存在已选摘要”。 4. 只记录布尔值或数量,不保存摘要原文和规格值原文。 ### 二、单条诊断记录方向确认 `AgentDiagnosticStore` 当前全局最多保留 50 条记录。一次颜色阶段写入多条度量事件会过快淘汰详情进入、规格面板、尺码发现等其他阶段证据,因此后续应调整为: - 一次 `collectColors` 最多写入 **1 条** `COLOR_DISCOVERY`; - `reason` 只表示最终终止原因; - 数量类数据必须进入独立字段,不再使用原因枚举承载。 应删除以下“指标型原因”: - `COLOR_ROW_VALUE_COUNT` - `COLOR_SELECTED_VALUE_COUNT` - `COLOR_HORIZONTAL_SWIPE_COUNT` - `COLOR_VERTICAL_SWIPE_COUNT` `COLOR_FOUND` 不再同时充当数量指标。正常结束时由实际终止原因表达,例如稳定边界为 `COLOR_EDGE_REACHED`、达到上限为 `COLOR_SCAN_LIMIT`。 ### 三、建议的单记录字段 单条 `COLOR_DISCOVERY` 建议包含以下脱敏字段: - `row_count`:识别到的颜色行数; - `row_value_counts`:各行值数量的紧凑摘要,只允许数字和分隔符,并限制长度; - `clickable_color_count`:解析到的可点击颜色值数量; - `non_clickable_candidate_count`:颜色区间内可见但未解析为可点击规格值的候选数量; - `initial_selected_color_count`:首次颜色点击前已选颜色值数量; - `initial_selected_size_count`:首次颜色点击前已选尺码值数量; - `selected_summary_present`:是否存在以 `selection.selectedPrefixes` 开头的已选摘要; - `horizontal_swipe_count`:颜色发现阶段实际成功的横向滑动次数; - 复用既有 `elapsed_ms`; - 复用 `reason` 保存唯一终止原因。 本阶段没有颜色纵向发现,`vertical_swipe_count` 恒为 0,没有诊断价值,应暂不新增;待纵向发现分支正式实施时再加入。 继续禁止保存颜色/尺码文案、价格、摘要原文、坐标、链接、goods_id、控件树、XML 和截图。 ### 四、数据库迁移门禁 上述独立字段需要修改 Agent 本地 SQLite `agent_diagnostic` 表,这与工单正文现有“**不修改数据库结构**”描述冲突,也属于项目规则要求人工确认的数据库迁移。 因此后续实施前必须: 1. 先修订 #124 的范围、非目标、风险与回退说明,明确仅新增本地诊断表的可空字段,不涉及服务端数据库; 2. 获得用户对本地 SQLite 增量迁移的明确确认; 3. `DATABASE_VERSION` 从 1 升级到 2; 4. 实现并测试 `v1 → v2` 的非破坏性 `ALTER TABLE ADD COLUMN` 迁移; 5. 保留已有诊断记录,不删除、不重建表; 6. 不得复用或曲解 `clipboard* / target* / candidateCount / attempt` 等旧字段来塞入颜色指标。 在取得迁移确认前,不继续修改代码。 ### 五、诊断能力边界 本阶段明确不执行颜色纵向滑动,因此单次诊断不能独立证明“纵向滑动后出现新行”,也不能保证一次记录完成 A/B/C 三选一。 诊断只能: - 通过不可点击候选数为分支 B 提供支持证据; - 通过首次点击前的尺码/颜色选中数及已选摘要为分支 C 提供支持证据; - 当 B/C 均无明显证据时,结合手机界面人工观察,进一步验证分支 A。 这些读数是诊断证据,不是充分因果证明,不得据此自动执行取消尺码、放宽解析或纵向滚动修复。 ### 六、真机读取与验收补充 当前诊断只保存在 Agent 本地数据库,没有 Admin/API 查看入口。装机验收前必须在工单写明可复现的读取路径: - 使用 Debug APK; - 明确 `adb shell run-as <最终包名>` 读取或导出 `goauto_diagnostics.db` 的具体命令; - 验证同一任务只产生一条 `COLOR_DISCOVERY`; - 记录设备、Agent 0.9.12(或修订后的新版本)、任务号和规则快照; - 不把数据库文件、规格文案或其他任务原始数据上传工单,只回写脱敏聚合读数。 若正式 APK 不允许 `run-as`,则本工单必须另行确认安全的只读诊断出口;不能只声称“已落库”后直接验收。 ### 七、修订后的测试要求 - 一次颜色采集只产生一条 `COLOR_DISCOVERY`。 - 首次点击前颜色、尺码选中数分别正确,后续 Agent 点击不改变初始读数。 - 后代节点暴露的 `selected/checked` 继续通过现有 Parser 规范化结果生效。 - “请选择”不记为已选摘要,“已选”才记为已选摘要。 - `v1 → v2` 迁移保留旧记录并补齐可空列。 - 诊断内容不包含任何规格文案、价格与原始页面结构。 - 模拟诊断写入失败时采集行为和结果不变。 - `collectColors` 遍历、`PddScreenParser.parse` 判定条件和 `swipeSpec` 仍不得改变。 ### 状态 提交 `9bb19b4` 已完成首版诊断,但按本评论发现的问题,暂不进入真机验收。下一步应先由用户确认是否允许 Agent 本地 SQLite `v1 → v2` 增量迁移;确认后仅修订第 1 项诊断,不实施 #124 第 2~5 项。
Author
Owner

争议裁决与迁移授权(以本评论为准)

针对修订评论中的两处判断分歧,逐条核对代码后结论如下;同时用户已授权本地诊断库迁移。后续实施以本评论为准,覆盖 #5174 与修订评论中被推翻的部分。

一、撤回 #5174 的第 1 点(我方判断有误)

#5174 称「当前实现只检查规格节点自身,未检查后代节点」,该判断不成立,予以撤回。

PddProductDetailCollector.kt:151-152 在 parse 构造规范化节点时已完成折叠:

selected = node.selected || descendants.any(SnapshotNode::selected),
checked  = node.checked  || descendants.any(SnapshotNode::checked),

因此 VisibleSpecValue.node.selected/checked 已含后代状态,不需要在诊断层重复遍历后代,也不得为此改动 parse。

修订评论对真实问题的定位正确并予采纳:diagnosticSelectedValues 使用 maxOf 跨整个采集过程取最大值,Agent 自身点击后的快照会污染「进入面板时是否已默认选中」这一证据。按修订要求执行:初始选中态只取首次颜色点击之前的快照,颜色与尺码分别记录。

二、纠正修订评论第一节第 3 条(该条判断有误)

修订评论称「selectedSummary 也可能匹配『请选择』,因此不能直接作为已选证据」,该判断不成立。

PddProductDetailCollector.kt:290-292:

selectedSummary = labels.firstOrNull {
    val compact = it.replace(" ", "")
    textAliases.selection.selectedPrefixes.any(compact::startsWith)
}

RuleContract.kt:90-91 中两个前缀集是分开的:

  • summaryPrefixes = ["已选", "请选择", "已選", "請選擇"]
  • selectedPrefixes = ["已选", "已選"]

selectedSummary 使用的是 selectedPrefixes,本就只匹配「已选」,不会匹配「请选择」。

因此:

  • selected_summary_present 直接取 screen.selectedSummary != null 即可,不需要额外的前缀再判定;
  • 不得为此修改 selectedSummary 的取值语义。该字段还被 :1311 的颜色选中确认与 :1419 的屏幕签名使用,改动会溢出本工单范围并影响既有采价与稳定性判定。

修订评论要求「不保存摘要原文、只记布尔值或数量」的部分予以保留,与安全边界一致。

三、数据库迁移授权

用户已于 2026-08-28 明确授权 Agent 本地诊断库 goauto_diagnostics.db 执行 v1 → v2 增量迁移。授权范围与约束:

  1. 仅对 Agent 本地 SQLite agent_diagnostic 表新增可空列,只允许 ALTER TABLE ADD COLUMN。
  2. 不得删除或重建表、不得改动既有列、不得清空既有记录。
  3. AgentDiagnosticStore.kt:190 的 DATABASE_VERSION 由 1 升为 2;:139 现为 onUpgrade(...) = Unit 空实现,必须替换为真实的 v1 → v2 迁移逻辑,否则升级后新列缺失将导致写入失败。
  4. 迁移必须幂等,并覆盖「全新安装走 onCreate」与「旧库升级走 onUpgrade」两条路径的测试。
  5. 不涉及服务端数据库、共享 API 与任何业务数据;最坏情况仅影响本地诊断历史。
  6. 保留修订评论的约束:不得复用或曲解 clipboard* / target* / candidateCount / attempt 等既有字段承载颜色指标。

据此,工单正文「非目标」中的「不修改数据库结构」需同步修订为「不修改服务端数据库与共享 API 字段;允许 Agent 本地诊断库新增可空列的增量迁移」。

四、其余修订内容一并确认

修订评论中下列各项予以确认,无需再讨论:

  • 单次 collectColors 最多写入 1 条 COLOR_DISCOVERY;reason 只表示唯一终止原因。
  • 删除指标型原因枚举:COLOR_ROW_VALUE_COUNT、COLOR_SELECTED_VALUE_COUNT、COLOR_HORIZONTAL_SWIPE_COUNT、COLOR_VERTICAL_SWIPE_COUNT;COLOR_FOUND 不再兼任数量指标。
  • vertical_swipe_count 本阶段不新增,待纵向发现分支实施时再加。
  • 第三节列出的单记录字段清单予以采纳(按第二节调整 selected_summary_present 的取值方式)。
  • 诊断只提供支持证据,不构成充分因果证明;不得据此自动执行取消尺码、放宽解析或纵向滚动等修复。分支 A 仍需结合手机界面人工观察确认。
  • 装机验收前必须在工单写明可复现的诊断读取路径与命令;若正式 APK 不允许 run-as,需另行确认安全的只读导出方式,不得仅声称「已落库」即进入验收。
  • 第七节的测试要求全部保留,并增加迁移的两条路径测试。

五、下一步

按本评论修订第 1 项诊断实现,仍不实施 #124 第 2~5 项。完成后装机采集一次原问题商品,回写脱敏聚合读数(不上传数据库文件与任何规格文案),再据此确定进入 A / B / C 哪个分支。

## 争议裁决与迁移授权(以本评论为准) 针对修订评论中的两处判断分歧,逐条核对代码后结论如下;同时用户已授权本地诊断库迁移。后续实施以本评论为准,覆盖 #5174 与修订评论中被推翻的部分。 ### 一、撤回 #5174 的第 1 点(我方判断有误) #5174 称「当前实现只检查规格节点自身,未检查后代节点」,**该判断不成立,予以撤回**。 `PddProductDetailCollector.kt:151-152` 在 `parse` 构造规范化节点时已完成折叠: ```kotlin selected = node.selected || descendants.any(SnapshotNode::selected), checked = node.checked || descendants.any(SnapshotNode::checked), ``` 因此 `VisibleSpecValue.node.selected/checked` 已含后代状态,**不需要在诊断层重复遍历后代**,也不得为此改动 `parse`。 修订评论对真实问题的定位正确并予采纳:`diagnosticSelectedValues` 使用 `maxOf` 跨整个采集过程取最大值,Agent 自身点击后的快照会污染「进入面板时是否已默认选中」这一证据。按修订要求执行:初始选中态只取**首次颜色点击之前**的快照,颜色与尺码分别记录。 ### 二、纠正修订评论第一节第 3 条(该条判断有误) 修订评论称「`selectedSummary` 也可能匹配『请选择』,因此不能直接作为已选证据」,**该判断不成立**。 `PddProductDetailCollector.kt:290-292`: ```kotlin selectedSummary = labels.firstOrNull { val compact = it.replace(" ", "") textAliases.selection.selectedPrefixes.any(compact::startsWith) } ``` `RuleContract.kt:90-91` 中两个前缀集是分开的: - `summaryPrefixes = ["已选", "请选择", "已選", "請選擇"]` - `selectedPrefixes = ["已选", "已選"]` `selectedSummary` 使用的是 `selectedPrefixes`,本就只匹配「已选」,不会匹配「请选择」。 **因此:** - `selected_summary_present` 直接取 `screen.selectedSummary != null` 即可,不需要额外的前缀再判定; - **不得**为此修改 `selectedSummary` 的取值语义。该字段还被 `:1311` 的颜色选中确认与 `:1419` 的屏幕签名使用,改动会溢出本工单范围并影响既有采价与稳定性判定。 修订评论要求「不保存摘要原文、只记布尔值或数量」的部分**予以保留**,与安全边界一致。 ### 三、数据库迁移授权 用户已于 2026-08-28 明确授权 Agent 本地诊断库 `goauto_diagnostics.db` 执行 `v1 → v2` 增量迁移。授权范围与约束: 1. 仅对 Agent 本地 SQLite `agent_diagnostic` 表新增**可空列**,只允许 `ALTER TABLE ADD COLUMN`。 2. **不得**删除或重建表、不得改动既有列、不得清空既有记录。 3. `AgentDiagnosticStore.kt:190` 的 `DATABASE_VERSION` 由 1 升为 2;`:139` 现为 `onUpgrade(...) = Unit` 空实现,必须替换为真实的 `v1 → v2` 迁移逻辑,否则升级后新列缺失将导致写入失败。 4. 迁移必须幂等,并覆盖「全新安装走 `onCreate`」与「旧库升级走 `onUpgrade`」两条路径的测试。 5. 不涉及服务端数据库、共享 API 与任何业务数据;最坏情况仅影响本地诊断历史。 6. 保留修订评论的约束:不得复用或曲解 `clipboard*` / `target*` / `candidateCount` / `attempt` 等既有字段承载颜色指标。 据此,工单正文「非目标」中的「不修改数据库结构」需同步修订为「不修改服务端数据库与共享 API 字段;允许 Agent 本地诊断库新增可空列的增量迁移」。 ### 四、其余修订内容一并确认 修订评论中下列各项予以确认,无需再讨论: - 单次 `collectColors` 最多写入 1 条 `COLOR_DISCOVERY`;`reason` 只表示唯一终止原因。 - 删除指标型原因枚举:`COLOR_ROW_VALUE_COUNT`、`COLOR_SELECTED_VALUE_COUNT`、`COLOR_HORIZONTAL_SWIPE_COUNT`、`COLOR_VERTICAL_SWIPE_COUNT`;`COLOR_FOUND` 不再兼任数量指标。 - `vertical_swipe_count` 本阶段不新增,待纵向发现分支实施时再加。 - 第三节列出的单记录字段清单予以采纳(按第二节调整 `selected_summary_present` 的取值方式)。 - 诊断只提供支持证据,不构成充分因果证明;不得据此自动执行取消尺码、放宽解析或纵向滚动等修复。分支 A 仍需结合手机界面人工观察确认。 - 装机验收前必须在工单写明可复现的诊断读取路径与命令;若正式 APK 不允许 `run-as`,需另行确认安全的只读导出方式,不得仅声称「已落库」即进入验收。 - 第七节的测试要求全部保留,并增加迁移的两条路径测试。 ### 五、下一步 按本评论修订第 1 项诊断实现,仍**不实施** #124 第 2~5 项。完成后装机采集一次原问题商品,回写脱敏聚合读数(不上传数据库文件与任何规格文案),再据此确定进入 A / B / C 哪个分支。
Author
Owner

继续实施第 1 项诊断修订。已确认用户本次指令授权 Agent 本地 goauto_diagnostics.db 执行受限的 v1 → v2 增量迁移。范围严格按 #5192:单条 COLOR_DISCOVERY、独立脱敏字段、初始颜色/尺码选中态、迁移与读取路径测试;不修改 collectColors 遍历算法、parse 判定条件或 swipeSpec,不实施第 2~5 项。

继续实施第 1 项诊断修订。已确认用户本次指令授权 Agent 本地 `goauto_diagnostics.db` 执行受限的 `v1 → v2` 增量迁移。范围严格按 #5192:单条 `COLOR_DISCOVERY`、独立脱敏字段、初始颜色/尺码选中态、迁移与读取路径测试;不修改 `collectColors` 遍历算法、`parse` 判定条件或 `swipeSpec`,不实施第 2~5 项。
Author
Owner

第 1 项实施完成,等待真机验收

已按最新修订方案完成“颜色阶段诊断”,本次没有修改 collectColors 的颜色遍历逻辑、解析判定条件或 swipeSpec。

实现

  • Agent 版本升级为 0.9.13(versionCode 26)。
  • 每次 collectColors 正常结束仅写入 1 条 COLOR_DISCOVERY 诊断记录。
  • 新增脱敏聚合字段:
    • color_row_count
    • color_row_value_counts
    • clickable_color_count
    • non_clickable_color_candidate_count
    • initial_selected_color_count
    • initial_selected_size_count
    • selected_summary_present
    • horizontal_swipe_count
  • 初始颜色/尺码选中数量在第一次 Agent 颜色点击前采集;后续点击不会污染初始选中证据。
  • selected_summary_present 仅依据解析器已经识别的“已选”摘要;“请选择”不会误判。
  • reason 仅保留终止原因,不再用独立记录表达行数、选中数或滑动数。
  • 本地 goauto_diagnostics.db 由 v1 升级至 v2,使用只增加可空列的迁移;重复执行不会重复加列,旧记录保留。
  • 诊断内容不包含原始控件树、截图、规格文本或账号信息。

验证

  • 定向单元测试通过:
    • PddProductDetailCollectorTest
    • AgentDiagnosticRecorderTest
    • AgentDiagnosticStoreMigrationTest
  • 迁移测试覆盖:
    • v2 新建表与字段读写;
    • v1 带旧记录升级后记录保留;
    • 重复升级幂等。
  • python dev_scripts/harness.py check --strict:通过。
  • .\scripts\verify.ps1 -Component android:通过,Debug/Release 单元测试及 Debug APK 构建成功。
  • APK:android/app/build/outputs/apk/debug/app-debug.apk。

文档与提交

  • 长期排错事实已更新至 Wiki Troubleshooting,在线 revision:a8d4790811aa825c78830cb9c71c6b21723e4584。
  • 已同步本地镜像并通过一致性检查。说明:本机 Python urllib 经代理发生 TLS 失败,因此在不改变 harness 同步逻辑的前提下,用 curl 作为只读 Wiki GET 传输完成同一轮 sync / sync --check。
  • 提交:d718c957bc223bc2e55c4ee6bc42855e11237fb3
  • 已推送至 origin/main。

未验证与停止点

尚未在原问题商品和真机上读取本次聚合诊断。工单保持待验收;下一步仅安装 0.9.13 Debug APK、复现原商品并按 Wiki 命令读取最新一条脱敏 COLOR_DISCOVERY 记录。在用户确认诊断分支前,不实施 #124 第 2~5 项,也不修改遍历、解析或手势逻辑。

## 第 1 项实施完成,等待真机验收 已按最新修订方案完成“颜色阶段诊断”,本次没有修改 `collectColors` 的颜色遍历逻辑、解析判定条件或 `swipeSpec`。 ### 实现 - Agent 版本升级为 **0.9.13(versionCode 26)**。 - 每次 `collectColors` 正常结束仅写入 **1 条** `COLOR_DISCOVERY` 诊断记录。 - 新增脱敏聚合字段: - `color_row_count` - `color_row_value_counts` - `clickable_color_count` - `non_clickable_color_candidate_count` - `initial_selected_color_count` - `initial_selected_size_count` - `selected_summary_present` - `horizontal_swipe_count` - 初始颜色/尺码选中数量在第一次 Agent 颜色点击前采集;后续点击不会污染初始选中证据。 - `selected_summary_present` 仅依据解析器已经识别的“已选”摘要;“请选择”不会误判。 - `reason` 仅保留终止原因,不再用独立记录表达行数、选中数或滑动数。 - 本地 `goauto_diagnostics.db` 由 v1 升级至 v2,使用只增加可空列的迁移;重复执行不会重复加列,旧记录保留。 - 诊断内容不包含原始控件树、截图、规格文本或账号信息。 ### 验证 - 定向单元测试通过: - `PddProductDetailCollectorTest` - `AgentDiagnosticRecorderTest` - `AgentDiagnosticStoreMigrationTest` - 迁移测试覆盖: - v2 新建表与字段读写; - v1 带旧记录升级后记录保留; - 重复升级幂等。 - `python dev_scripts/harness.py check --strict`:通过。 - `.\scripts\verify.ps1 -Component android`:通过,Debug/Release 单元测试及 Debug APK 构建成功。 - APK:`android/app/build/outputs/apk/debug/app-debug.apk`。 ### 文档与提交 - 长期排错事实已更新至 Wiki **Troubleshooting**,在线 revision:`a8d4790811aa825c78830cb9c71c6b21723e4584`。 - 已同步本地镜像并通过一致性检查。说明:本机 Python urllib 经代理发生 TLS 失败,因此在不改变 harness 同步逻辑的前提下,用 curl 作为只读 Wiki GET 传输完成同一轮 `sync` / `sync --check`。 - 提交:`d718c957bc223bc2e55c4ee6bc42855e11237fb3` - 已推送至 `origin/main`。 ### 未验证与停止点 尚未在原问题商品和真机上读取本次聚合诊断。工单保持待验收;下一步仅安装 0.9.13 Debug APK、复现原商品并按 Wiki 命令读取最新一条脱敏 `COLOR_DISCOVERY` 记录。在用户确认诊断分支前,不实施 #124 第 2~5 项,也不修改遍历、解析或手势逻辑。
Author
Owner

实施完成,待验收

已按确认范围完成纵向/网格颜色发现、动态行发现与稳定终止,未扩展解析口径、服务端接口、规则结构或数据库。

实现

  • 每次颜色点击或翻页后重新解析全部可见颜色行,以全局已尝试集合去重,避免选中项消失或布局重排后静默跳过后续颜色。
  • 单列多行直接进行有界纵向发现,不执行无效横向滑动;网格/多值行保留既有有界横向发现。
  • 纵向发现复用规则快照的 specVerticalSwipes 与 stableEdgeReads,通过连续稳定视口签名终止,并保留扫描上限、容器不可用、滑动失败等明确诊断原因。
  • 颜色采集结束后将规格面板归顶,再进入尺码发现。
  • Agent 版本升级为 0.9.14(versionCode 27)。

自动验证

  • .\gradlew.bat :app:testDebugUnitTest --tests cn.ilapage.goauto.agent.PddProductDetailCollectorTest:通过。
  • .\scripts\verify.ps1 -Component android:通过;Debug/Release 共 162 个测试通过,Debug APK 构建成功。
  • python dev_scripts/harness.py check --strict:通过。
  • python dev_scripts/harness.py sync --check:通过。
  • git diff --check:通过。

新增回归覆盖单列纵向分页和网格纵向视口变化;既有横向颜色回归继续通过。

同商品真机验证

设备:PKG110;PDD 商品、规则和设备与任务 #87 相同;Agent 0.9.14。

  • 旧任务 #87:completed_partial,最终结果仅 1 个颜色、1 条颜色价格、1 个完整 SKU。
  • 新任务 #89:completed_partial,最终结果为 6 个颜色、6 条稳定颜色价格、6 个完整 SKU。
  • #89 颜色诊断:COLOR_EDGE_REACHED;首屏 6 行,行值数 1,1,1,1,1,1;可点击 6、不可点击候选 3;初始已选颜色/尺码/摘要均存在;横向滑动 0;耗时 11248ms。
  • partial 仅因同商品仍缺 shopName、reviewCount,本工单颜色目标已验证。
  • 任务 #88 首次尝试因上次遗留规格面板覆盖商品页分享入口,在 PAGE_STABILITY/TARGET_NOT_FOUND 失败;关闭遗留面板后同商品任务 #89 成功完成,未作为颜色逻辑结果计入。

文档与提交

  • Wiki:Business-Rules-and-Glossary,revision b330f2be68cb2eddb929db2cb6021cf9f9b527ad;已在线回读并同步本地镜像。
  • 提交:c2a1363f(已推送到 origin/main)。

未验证范围

本轮未在其他设备/ROM 上复测,也未另找一个真实横向多颜色商品真机复测;横向路径由既有单元回归覆盖。工单保持打开,等待人工验收。

## 实施完成,待验收 已按确认范围完成纵向/网格颜色发现、动态行发现与稳定终止,未扩展解析口径、服务端接口、规则结构或数据库。 ### 实现 - 每次颜色点击或翻页后重新解析全部可见颜色行,以全局已尝试集合去重,避免选中项消失或布局重排后静默跳过后续颜色。 - 单列多行直接进行有界纵向发现,不执行无效横向滑动;网格/多值行保留既有有界横向发现。 - 纵向发现复用规则快照的 `specVerticalSwipes` 与 `stableEdgeReads`,通过连续稳定视口签名终止,并保留扫描上限、容器不可用、滑动失败等明确诊断原因。 - 颜色采集结束后将规格面板归顶,再进入尺码发现。 - Agent 版本升级为 0.9.14(versionCode 27)。 ### 自动验证 - `.\gradlew.bat :app:testDebugUnitTest --tests cn.ilapage.goauto.agent.PddProductDetailCollectorTest`:通过。 - `.\scripts\verify.ps1 -Component android`:通过;Debug/Release 共 162 个测试通过,Debug APK 构建成功。 - `python dev_scripts/harness.py check --strict`:通过。 - `python dev_scripts/harness.py sync --check`:通过。 - `git diff --check`:通过。 新增回归覆盖单列纵向分页和网格纵向视口变化;既有横向颜色回归继续通过。 ### 同商品真机验证 设备:PKG110;PDD 商品、规则和设备与任务 #87 相同;Agent 0.9.14。 - 旧任务 #87:`completed_partial`,最终结果仅 1 个颜色、1 条颜色价格、1 个完整 SKU。 - 新任务 #89:`completed_partial`,最终结果为 6 个颜色、6 条稳定颜色价格、6 个完整 SKU。 - #89 颜色诊断:`COLOR_EDGE_REACHED`;首屏 6 行,行值数 `1,1,1,1,1,1`;可点击 6、不可点击候选 3;初始已选颜色/尺码/摘要均存在;横向滑动 0;耗时 11248ms。 - partial 仅因同商品仍缺 `shopName`、`reviewCount`,本工单颜色目标已验证。 - 任务 #88 首次尝试因上次遗留规格面板覆盖商品页分享入口,在 `PAGE_STABILITY/TARGET_NOT_FOUND` 失败;关闭遗留面板后同商品任务 #89 成功完成,未作为颜色逻辑结果计入。 ### 文档与提交 - Wiki:`Business-Rules-and-Glossary`,revision `b330f2be68cb2eddb929db2cb6021cf9f9b527ad`;已在线回读并同步本地镜像。 - 提交:`c2a1363f`(已推送到 `origin/main`)。 ### 未验证范围 本轮未在其他设备/ROM 上复测,也未另找一个真实横向多颜色商品真机复测;横向路径由既有单元回归覆盖。工单保持打开,等待人工验收。
Author
Owner

更正上一条中的提交标识:完整提交为 c2a1363561bb3495174f888f75643821fdb924e7(短哈希 c2a1363),已推送至 origin/main。

更正上一条中的提交标识:完整提交为 `c2a1363561bb3495174f888f75643821fdb924e7`(短哈希 `c2a1363`),已推送至 `origin/main`。
Author
Owner

用户于 2026-08-28 明确确认本工单验收通过。按项目流程记录验收结论并关闭工单;本次仅更新工单状态,无新增长期文档事实,不重复同步 Wiki。

用户于 2026-08-28 明确确认本工单验收通过。按项目流程记录验收结论并关闭工单;本次仅更新工单状态,无新增长期文档事实,不重复同步 Wiki。
ila closed this issue 2026-08-28 15:07:10 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#124