缺陷:CG30 最新 Agent 对存在且可用的精确 SKU 仍重复探测并失败 #164

Open
opened 2026-08-31 10:21:48 +08:00 by ila · 3 comments
Owner

Gitea MCP 未向当前会话暴露,按仓库规则回退项目根目录安全配置与 Gitea API 维护本工单;凭据未写入工单、代码或日志。

2026-08-31 第二次方案修订(待用户确认):保留参考 D:\chengma\cmautobuy\client 的失败分阶段和容器内有界搜索思路,但不直接移植其无限父链、分隔符子串匹配、XML 落盘或 Windows 繁简转换。规格再次探测由服务端按任务类型、规格来源与已固化决策显式裁决;普通就地重试不恢复探测资格。阶段 A 固定为契约与可观测性修复,不预先改变滑动行为;阶段 B 才依据 CG30 的真实阶段证据做最小行为修复。

原始需求摘要

来源:用户于 2026-08-31 反馈“最新版本 Agent,CG30 还是不能精确选择商品规格”,在只读分析后明确要求建工单修复。

目的:修复 CG30 已收到干净、存在且可用的精确 PDD SKU 后,Agent 仍把选择判定为失败并重复规格探测的问题;保留“不猜测、不点击相近候选”和永久禁止支付边界。

基线与已核实事实

代码基线:4e05048(2026-08-31);相对 d8e13da 新增的是无关 Web 提交,本文涉及的 Android/Server 采购代码未变化。#160 已由 67f3a74 实现但仍待人工验收。核验日期 2026-08-31。

  • 设备:数据库 device 5,型号 PKG110(用户称 CG30),Android 16,Agent 0.9.29,PDD 8.22.0;现场核验时在线。
  • 最新失败任务:purchase task 30,目标 黑色 / 3XL,固化映射 黑色 / 3XL 建议:150斤-180斤,来源 ai_match;映射来自 Agent 当次探测候选,AI 只返回候选集合中的精确原文。
  • 历史采集 task 97 的完整 SKU 中存在 黑色 / 3XL 建议:150斤-180斤,available=true、complete=true,当前证据不支持“规格组合不存在”。
  • task 30 attempt 1 返回 spec_probe_completed 并固化精确决策;attempt 2、3 又返回 spec_probe_completed,最终被服务端统一收敛为 PURCHASE_SPEC_NOT_MATCHED / 再次执行仍未能精确选择商品规格,请检查商品规格。

代码事实:

  • PurchaseRehearsalExecutor.kt:103:只要规则含 probeSpecs,purchase 阶段任何 PURCHASE_SPEC_NOT_MATCHED 都会转成 probeOutcome();live 默认规则确实含该动作。
  • purchase/lifecycle.go:335-343:任务已有 SpecDecisionRequestID 时,第二次 spec_probe_completed 被 fail-closed,并写死统一错误消息。
  • 当前 Agent payload 不包含“是否仍允许一次规格探测”;Android 不能仅凭 phase 或映射是否非空可靠推导该资格。purchase/reset.go 的普通就地重试不清除 SpecDecisionRequestID,并按长期业务规则保留目标规格、已映射规格及其他业务快照。
  • PurchaseRehearsalExecutor.kt:337-356:当前选中复核只检查候选节点自身 selected/checked,短摘要兜底依赖当前可见候选唯一;选中态挂在规格卡片祖先、候选离屏或面板重绘时可能证据不足。
  • PddProductDetailCollector.kt:273:#160 尾价规范化只作用于页面 size 值;任务 mappedSize 未在选择边界应用同一规范化,旧快照可能与清洁页面值比较失败。
  • live 默认规则的 openSpecPanel 带固定 up×2,locateExactSpec 另有全屏 DOWN×3 / UP×6;其对 CG30 失败的实际影响尚未由结构化阶段证据确认。

参考实现边界

只读参考 D:\chengma\cmautobuy\client 的以下思路:

  • 规格失败按目标不可见、候选歧义、安全点击目标缺失、点击后未确认等阶段分类。
  • 滚动搜索绑定规格容器,每次滑动后重新读取并以可见签名稳定判断边界。
  • 选颜色导致面板重绘后先恢复规格区域,再选尺码。

明确不直接移植:

  • 参考实现 _label_matches 允许带分隔符边界的子串匹配,本项目仍要求完整规范化候选严格相等。
  • 参考实现 _target_is_selected 会沿父链持续向上检查;本项目必须把范围限制在目标规格卡片内,不能越过维度/滚动/面板容器。
  • 不保存 XML、原始控件树或整屏截图。
  • 不引入依赖 Windows API 的繁简转换;如确有需要另建工单。

判断边界

  • 已确认:task 30 收到精确干净候选且完整 SKU 存在;失败发生在 Android 选择/复核路径,真实子阶段被二次探测覆盖。
  • 尚未确认:失败具体属于目标不可见、点击节点失效、点击动作失败、选中态挂在卡片祖先、候选离屏还是其组合。
  • 阶段 A 只恢复可见性和统一比较语义;不提前删除 up×2 或改造滚动行为,以免改变现场后无法确定原根因。
  • 禁止为诊断保存规格原文、坐标、控件树、截图、账号、地址、订单或支付信息。

目标

  1. purchase 阶段真实规格失败必须可区分、可回写,不再被无条件二次探测覆盖。
  2. 规格探测资格由服务端按任务类型、规格来源、规则能力和已固化决策显式下发;已经固化过一次探测决策的任务及 stock/direct_select 任务不得再次探测。
  3. 任务目标和页面规格在选择边界使用同一套 #160 安全尾价规范化,但历史快照保持不可变。
  4. 根据阶段 A 的 CG30 证据实施最小必要的选中确认或容器搜索修复,不放宽候选定位与点击的严格相等语义。

非目标

  • 不修改 AI 匹配策略、置信度或候选约束。
  • 不修改 task 28、30 及任何历史 task/attempt/规格决策快照。
  • 不做模糊、子串、前缀、编辑距离或相近规格点击;不引入繁简归一化。
  • 不增加 OCR/VLM,不保存控件树或整屏截图。
  • 不修改地址、不创建订单、不支付。
  • 不顺带处理商品采集、价格、地址或订单结果问题。

前置依赖与并行性

  • 依赖 #160 的安全尾价规范化和主 token 边界,以提交 67f3a74 为实现基线。
  • 阶段 B 依赖阶段 A 的 CG30 安全演练结果,不可提前实施。
  • 与修改 Android 采购选择/复核代码或采购任务结果契约的任务不可并行。

固定实施方案

阶段 A:契约与可观测性修复

  1. 稳定失败阶段

    Android 规格选择引入五态:

    • target_not_visible:完成规定的有界搜索后仍没有完整严格相等目标;
    • target_ambiguous:同维度存在多个严格等价候选;
    • safe_target_missing:目标可见,但不能确定唯一、可靠的目标规格卡片或可点击祖先;
    • click_failed:已确定安全目标,但 fresh 重定位或点击动作失败;仅允许记录 root_unavailable、target_stale、no_clickable_ancestor、action_click_false 等稳定子原因;
    • selection_unconfirmed:点击动作已成功,但规定时间内没有取得可靠选中证据。

    只上报稳定阶段、稳定子原因、taskId、deviceId、attempt 与耗时;清理现有错误消息中的规格原文。

  2. 服务端显式探测资格矩阵

    • TaskPayload 新增 specResolutionAllowed,Android PurchaseAgentTask 同步接收。
    • SpecDecisionRequestID != nil:固定为 false。普通就地重试不清除该字段、不恢复资格,也不改变目标规格、已映射规格或规格决策快照。
    • taskType=stock 或 specSource=direct_select:固定为 false。备货任务必须执行用户指定的精确规格,页面不存在时明确失败,不得自动改成 AI 或相近候选。
    • taskType=syb_order、规则具备 purchase.spec-probe.v1、SpecDecisionRequestID == nil 且规格来源允许既有慢路径时:返回 true。unresolved 初始探测和已有映射在真实页面目标不可见时的一次慢路径,均由服务端状态裁决。
    • 其他组合默认 false;不得由 Android 根据非空映射、phase 或错误文案自行扩大资格。
    • Android 只有在失败阶段为 target_not_visible 且 specResolutionAllowed=true 时,才返回 spec_probe_completed;其他四态或资格为 false 时直接提交真实失败。
    • 旧 Agent 在资格已经用尽后仍提交第二次探测时,服务端继续 fail-closed,但使用稳定的“重复探测被拒绝”错误码/原因,不再冒充新的选择根因。
    • 若同一任务确需重新匹配,不得通过普通就地重试改写;必须走创建新任务或商品替换后的继续采购流程。
  3. 服务端保留根因

    普通 failed 结果保留 Agent 的稳定规格失败阶段/子原因;不得再统一覆盖为“再次执行仍未能……”。共享字段和稳定错误码写入 Android Agent API 契约。

  4. 目标侧规范化

    在尺码定位、点击与复核边界,对任务目标和页面值应用同一 #160 安全尾价规范化。只剥离安全尾价,不改变建议说明、体重区间或其他规格身份;历史快照字段不改写。规范化后为空、残留货币符号,或多个原始候选折叠为同一值时安全失败。

  5. 阶段 A 不改滑动行为

    保留当前规则 up×2 和搜索行为,仅通过阶段枚举确认其影响;相关行为修复进入阶段 B。

阶段 A 的退出条件是:共享契约、五态与稳定子原因、探测资格矩阵、普通失败根因保留、重复探测 fail-closed 和目标侧规范化的自动化测试全部通过;随后仅使用 executionMode=rehearsal 且规则不包含 updateShippingAddress、createOrder、readOrderResult 的安全任务在 CG30 运行一次,取得明确失败阶段或证明现有行为已可完成复核。阶段 A 不要求在行为尚未修复时必然完成颜色、尺码与摘要复核,也不得因此提前进入整单“待验收”。不重试 task 30 的 live 任务,不修改地址、不创建订单、不支付。

阶段 A 的 CG30 证据必须写回工单;若仍需阶段 B,先把命中的真实阶段、最小修复项和未实施项写入工单并等待用户确认,再继续生产代码。

阶段 B:依据阶段 A 证据做最小行为修复

A. 若主要为 selection_unconfirmed

按以下顺序建立证据:

  1. 重新抓取完整规范化目标节点,优先检查节点自身 selected/checked。
  2. 只检查该节点用于点击的最近可点击规格卡片及卡片内部后代的 selected/checked;到维度容器、滚动容器或规格面板容器立即停止,禁止任意向根节点上溯。
  3. 若页面提供“已选”摘要,只能先按已确认分隔符解析成独立规格段,再对完整规范化目标严格相等;禁止 contains。无法可靠分段时不得使用该证据。
  4. 最后才允许使用 #160 的主 token 兜底:同一次页面/Activity/面板实例未变化,同维度新鲜候选集合中主 token 唯一,且摘要包含独立且严格相等的 token。两个候选共享同一主 token 时安全失败。

B. 若主要为 target_not_visible 或 safe_target_missing

  • 识别并绑定规格面板及对应维度的滚动容器,只在容器内部有界滑动。
  • 每次滑动后重新抓取、重新解析并重新定位容器;内部可见签名连续两次不变才认为到达该方向边界。
  • 颜色选择导致面板重绘后,重新确认同一商品页和规格面板,再恢复规格区域并选择尺码。
  • 根据证据决定是否移除默认规则固定 up×2;不得在证据出现前删除。

C. 若主要为 click_failed

只修复对应 fresh-node 重定位或最近可点击规格卡片选择问题;不得用坐标盲点、兄弟节点、相似文本或更宽松匹配兜底。

阶段 B 只实施真实阶段需要的最小项;未实施项及原因写回工单。

验收标准

阶段 A 退出条件

  • TaskPayload / Android payload 已新增并正确解析 specResolutionAllowed,资格矩阵覆盖 syb_order、stock/direct_select、已固化决策和普通就地重试。
  • 普通就地重试保留 SpecDecisionRequestID、目标规格、已映射规格和规格决策快照,探测资格不恢复。
  • 规格失败按五态及允许的稳定子原因上报;点击动作失败与点击成功但选中未确认可明确区分。
  • 只有 target_not_visible && specResolutionAllowed=true 才返回 spec_probe_completed;旧 Agent 重复探测仍 fail-closed,并使用明确的重复探测拒绝原因。
  • 服务端保留普通 failed 的真实根因,不再统一覆盖为“再次执行仍未能……”。
  • 旧快照含安全尾价时只在执行边界规范化比较,历史快照字段保持原样;规范化为空、残留货币或发生碰撞时安全失败。
  • Android 与 Server 对相同规范化、碰撞、资格和失败阶段样本的单元/契约测试通过,APK 与 Server 构建通过。
  • CG30 使用无地址、无订单动作的安全 rehearsal 取得明确五态结果或证明现有行为已可完成复核;证据已回写工单。
  • 阶段 A 未重试 task 30 live 任务,未修改地址、未创建订单、未支付。

阶段 B 及整单最终验收

  • 阶段 B 的实际改动严格来自阶段 A 的 CG30 证据,最小修复范围已经用户确认;未实施项及原因已记录。
  • CG30 / PDD 8.22.0 的安全 rehearsal 中,精确映射 黑色 / 3XL 建议:150斤-180斤 完成颜色、尺码与最终摘要复核,并在 verifyOrderSummary 后停止。
  • 父链证据只限最近可点击规格卡片,不越过维度、滚动或面板容器。
  • 摘要只按独立规格段或独立 token 严格相等确认,代码中不以 contains 判断完整规格已选。
  • XL 不匹配 2XL/3XL;两个候选共享主 token 时短摘要证据失败。
  • 若修改滚动行为,容器内到顶/到底、面板重绘后容器重定位和可见签名连续稳定均通过测试。
  • 诊断不包含规格原文、坐标、控件树、截图、账号、地址、订单或支付数据。
  • Wiki Android-Agent-API-Contract 已记录 specResolutionAllowed、资格矩阵、稳定失败阶段和重复探测拒绝语义,在线回读 revision 后完成一次 sync 和一次 sync --check。
  • 未修改地址、未创建订单、未支付;任何 live 行为仍需独立人工授权。

必测场景

  • 文本节点自身选中;仅最近可点击规格卡片选中;面板/列表祖先选中但规格卡片未选中,后者不得误判。
  • 摘要为独立完整目标;亮黑色 不得证明 黑色;摘要无法可靠分段时失败。
  • 同维度存在 XL/2XL/3XL;两个完整候选共享主 token XL 时失败。
  • 目标不存在、严格等价候选歧义、安全点击卡片缺失、fresh 节点失效、点击返回 false、点击成功但无选中证据分别进入正确阶段。
  • 探测资格为 true/false、首次探测固化后再次领取、旧 Agent 重复探测。
  • 旧目标含安全尾价;中间货币符号、规范化为空或规范化碰撞时失败。
  • 若阶段 B 修改滚动:容器内到顶/到底、面板重绘后容器重定位、可见签名连续两次稳定。

风险与安全门禁

  • 这是采购动作、安全判据与共享契约修改;实施前必须由用户确认本次修订方案。
  • 阶段 B 不得先于阶段 A 的 CG30 安全 rehearsal 证据。
  • 不得通过放宽相等判断提高成功率;证据不足必须失败。
  • 安全尾价规范化可能使多个原始候选折叠为同一值;该情况必须从偶然成功收敛为明确失败,禁止自动选择任一候选。实施前只读统计当前任务/商品影响范围,Android 与 Server 使用同一组 Unicode 空白、尾价、残留货币和碰撞样本验证,并把统计与结果回写工单。
  • 真机验证固定为无地址、无订单动作的 rehearsal;任何 live 重试、修改地址或创建待付款订单必须另行取得人工授权。
  • 永久禁止支付。

文档影响

有长期文档影响。 本单新增 specResolutionAllowed、稳定规格失败阶段以及重复探测拒绝语义,必须更新 Wiki Android-Agent-API-Contract;在线回读 revision 后执行一次 python dev_scripts/harness.py sync 和一次 sync --check,并把页面 revision 回写工单。

相邻问题(不在本单范围)

Android 侧繁简等价规格文本比较另建工单评估,本单不处理。

状态

进行中(2026-08-31 用户已确认,先执行阶段 A;阶段 B 仍以阶段 A 的 CG30 证据和再次确认作为门禁)。

> Gitea MCP 未向当前会话暴露,按仓库规则回退项目根目录安全配置与 Gitea API 维护本工单;凭据未写入工单、代码或日志。 > > **2026-08-31 第二次方案修订(待用户确认)**:保留参考 `D:\chengma\cmautobuy\client` 的失败分阶段和容器内有界搜索思路,但不直接移植其无限父链、分隔符子串匹配、XML 落盘或 Windows 繁简转换。规格再次探测由服务端按任务类型、规格来源与已固化决策显式裁决;普通就地重试不恢复探测资格。阶段 A 固定为契约与可观测性修复,不预先改变滑动行为;阶段 B 才依据 CG30 的真实阶段证据做最小行为修复。 ## 原始需求摘要 来源:用户于 2026-08-31 反馈“最新版本 Agent,CG30 还是不能精确选择商品规格”,在只读分析后明确要求建工单修复。 目的:修复 CG30 已收到干净、存在且可用的精确 PDD SKU 后,Agent 仍把选择判定为失败并重复规格探测的问题;保留“不猜测、不点击相近候选”和永久禁止支付边界。 ## 基线与已核实事实 代码基线:`4e05048`(2026-08-31);相对 `d8e13da` 新增的是无关 Web 提交,本文涉及的 Android/Server 采购代码未变化。#160 已由 `67f3a74` 实现但仍待人工验收。核验日期 2026-08-31。 - 设备:数据库 device 5,型号 `PKG110`(用户称 CG30),Android 16,Agent `0.9.29`,PDD `8.22.0`;现场核验时在线。 - 最新失败任务:purchase task 30,目标 `黑色 / 3XL`,固化映射 `黑色 / 3XL 建议:150斤-180斤`,来源 `ai_match`;映射来自 Agent 当次探测候选,AI 只返回候选集合中的精确原文。 - 历史采集 task 97 的完整 SKU 中存在 `黑色 / 3XL 建议:150斤-180斤`,`available=true`、`complete=true`,当前证据不支持“规格组合不存在”。 - task 30 attempt 1 返回 `spec_probe_completed` 并固化精确决策;attempt 2、3 又返回 `spec_probe_completed`,最终被服务端统一收敛为 `PURCHASE_SPEC_NOT_MATCHED / 再次执行仍未能精确选择商品规格,请检查商品规格`。 代码事实: - `PurchaseRehearsalExecutor.kt:103`:只要规则含 `probeSpecs`,purchase 阶段任何 `PURCHASE_SPEC_NOT_MATCHED` 都会转成 `probeOutcome()`;live 默认规则确实含该动作。 - `purchase/lifecycle.go:335-343`:任务已有 `SpecDecisionRequestID` 时,第二次 `spec_probe_completed` 被 fail-closed,并写死统一错误消息。 - 当前 Agent payload 不包含“是否仍允许一次规格探测”;Android 不能仅凭 `phase` 或映射是否非空可靠推导该资格。`purchase/reset.go` 的普通就地重试不清除 `SpecDecisionRequestID`,并按长期业务规则保留目标规格、已映射规格及其他业务快照。 - `PurchaseRehearsalExecutor.kt:337-356`:当前选中复核只检查候选节点自身 `selected/checked`,短摘要兜底依赖当前可见候选唯一;选中态挂在规格卡片祖先、候选离屏或面板重绘时可能证据不足。 - `PddProductDetailCollector.kt:273`:#160 尾价规范化只作用于页面 size 值;任务 `mappedSize` 未在选择边界应用同一规范化,旧快照可能与清洁页面值比较失败。 - live 默认规则的 `openSpecPanel` 带固定 `up×2`,`locateExactSpec` 另有全屏 `DOWN×3 / UP×6`;其对 CG30 失败的实际影响尚未由结构化阶段证据确认。 ## 参考实现边界 只读参考 `D:\chengma\cmautobuy\client` 的以下思路: - 规格失败按目标不可见、候选歧义、安全点击目标缺失、点击后未确认等阶段分类。 - 滚动搜索绑定规格容器,每次滑动后重新读取并以可见签名稳定判断边界。 - 选颜色导致面板重绘后先恢复规格区域,再选尺码。 明确不直接移植: - 参考实现 `_label_matches` 允许带分隔符边界的子串匹配,本项目仍要求完整规范化候选严格相等。 - 参考实现 `_target_is_selected` 会沿父链持续向上检查;本项目必须把范围限制在目标规格卡片内,不能越过维度/滚动/面板容器。 - 不保存 XML、原始控件树或整屏截图。 - 不引入依赖 Windows API 的繁简转换;如确有需要另建工单。 ## 判断边界 - 已确认:task 30 收到精确干净候选且完整 SKU 存在;失败发生在 Android 选择/复核路径,真实子阶段被二次探测覆盖。 - 尚未确认:失败具体属于目标不可见、点击节点失效、点击动作失败、选中态挂在卡片祖先、候选离屏还是其组合。 - 阶段 A 只恢复可见性和统一比较语义;不提前删除 `up×2` 或改造滚动行为,以免改变现场后无法确定原根因。 - 禁止为诊断保存规格原文、坐标、控件树、截图、账号、地址、订单或支付信息。 ## 目标 1. purchase 阶段真实规格失败必须可区分、可回写,不再被无条件二次探测覆盖。 2. 规格探测资格由服务端按任务类型、规格来源、规则能力和已固化决策显式下发;已经固化过一次探测决策的任务及 `stock/direct_select` 任务不得再次探测。 3. 任务目标和页面规格在选择边界使用同一套 #160 安全尾价规范化,但历史快照保持不可变。 4. 根据阶段 A 的 CG30 证据实施最小必要的选中确认或容器搜索修复,不放宽候选定位与点击的严格相等语义。 ## 非目标 - 不修改 AI 匹配策略、置信度或候选约束。 - 不修改 task 28、30 及任何历史 task/attempt/规格决策快照。 - 不做模糊、子串、前缀、编辑距离或相近规格点击;不引入繁简归一化。 - 不增加 OCR/VLM,不保存控件树或整屏截图。 - 不修改地址、不创建订单、不支付。 - 不顺带处理商品采集、价格、地址或订单结果问题。 ## 前置依赖与并行性 - 依赖 #160 的安全尾价规范化和主 token 边界,以提交 `67f3a74` 为实现基线。 - 阶段 B 依赖阶段 A 的 CG30 安全演练结果,不可提前实施。 - 与修改 Android 采购选择/复核代码或采购任务结果契约的任务不可并行。 ## 固定实施方案 ### 阶段 A:契约与可观测性修复 1. **稳定失败阶段** Android 规格选择引入五态: - `target_not_visible`:完成规定的有界搜索后仍没有完整严格相等目标; - `target_ambiguous`:同维度存在多个严格等价候选; - `safe_target_missing`:目标可见,但不能确定唯一、可靠的目标规格卡片或可点击祖先; - `click_failed`:已确定安全目标,但 fresh 重定位或点击动作失败;仅允许记录 `root_unavailable`、`target_stale`、`no_clickable_ancestor`、`action_click_false` 等稳定子原因; - `selection_unconfirmed`:点击动作已成功,但规定时间内没有取得可靠选中证据。 只上报稳定阶段、稳定子原因、taskId、deviceId、attempt 与耗时;清理现有错误消息中的规格原文。 2. **服务端显式探测资格矩阵** - `TaskPayload` 新增 `specResolutionAllowed`,Android `PurchaseAgentTask` 同步接收。 - `SpecDecisionRequestID != nil`:固定为 `false`。普通就地重试不清除该字段、不恢复资格,也不改变目标规格、已映射规格或规格决策快照。 - `taskType=stock` 或 `specSource=direct_select`:固定为 `false`。备货任务必须执行用户指定的精确规格,页面不存在时明确失败,不得自动改成 AI 或相近候选。 - `taskType=syb_order`、规则具备 `purchase.spec-probe.v1`、`SpecDecisionRequestID == nil` 且规格来源允许既有慢路径时:返回 `true`。`unresolved` 初始探测和已有映射在真实页面目标不可见时的一次慢路径,均由服务端状态裁决。 - 其他组合默认 `false`;不得由 Android 根据非空映射、`phase` 或错误文案自行扩大资格。 - Android 只有在失败阶段为 `target_not_visible` 且 `specResolutionAllowed=true` 时,才返回 `spec_probe_completed`;其他四态或资格为 false 时直接提交真实失败。 - 旧 Agent 在资格已经用尽后仍提交第二次探测时,服务端继续 fail-closed,但使用稳定的“重复探测被拒绝”错误码/原因,不再冒充新的选择根因。 - 若同一任务确需重新匹配,不得通过普通就地重试改写;必须走创建新任务或商品替换后的继续采购流程。 3. **服务端保留根因** 普通 failed 结果保留 Agent 的稳定规格失败阶段/子原因;不得再统一覆盖为“再次执行仍未能……”。共享字段和稳定错误码写入 Android Agent API 契约。 4. **目标侧规范化** 在尺码定位、点击与复核边界,对任务目标和页面值应用同一 #160 安全尾价规范化。只剥离安全尾价,不改变建议说明、体重区间或其他规格身份;历史快照字段不改写。规范化后为空、残留货币符号,或多个原始候选折叠为同一值时安全失败。 5. **阶段 A 不改滑动行为** 保留当前规则 `up×2` 和搜索行为,仅通过阶段枚举确认其影响;相关行为修复进入阶段 B。 阶段 A 的退出条件是:共享契约、五态与稳定子原因、探测资格矩阵、普通失败根因保留、重复探测 fail-closed 和目标侧规范化的自动化测试全部通过;随后仅使用 `executionMode=rehearsal` 且规则不包含 `updateShippingAddress`、`createOrder`、`readOrderResult` 的安全任务在 CG30 运行一次,取得明确失败阶段或证明现有行为已可完成复核。阶段 A 不要求在行为尚未修复时必然完成颜色、尺码与摘要复核,也不得因此提前进入整单“待验收”。不重试 task 30 的 live 任务,不修改地址、不创建订单、不支付。 阶段 A 的 CG30 证据必须写回工单;若仍需阶段 B,先把命中的真实阶段、最小修复项和未实施项写入工单并等待用户确认,再继续生产代码。 ### 阶段 B:依据阶段 A 证据做最小行为修复 #### A. 若主要为 `selection_unconfirmed` 按以下顺序建立证据: 1. 重新抓取完整规范化目标节点,优先检查节点自身 `selected/checked`。 2. 只检查该节点用于点击的**最近可点击规格卡片**及卡片内部后代的 `selected/checked`;到维度容器、滚动容器或规格面板容器立即停止,禁止任意向根节点上溯。 3. 若页面提供“已选”摘要,只能先按已确认分隔符解析成独立规格段,再对完整规范化目标严格相等;禁止 `contains`。无法可靠分段时不得使用该证据。 4. 最后才允许使用 #160 的主 token 兜底:同一次页面/Activity/面板实例未变化,同维度新鲜候选集合中主 token 唯一,且摘要包含独立且严格相等的 token。两个候选共享同一主 token 时安全失败。 #### B. 若主要为 `target_not_visible` 或 `safe_target_missing` - 识别并绑定规格面板及对应维度的滚动容器,只在容器内部有界滑动。 - 每次滑动后重新抓取、重新解析并重新定位容器;内部可见签名连续两次不变才认为到达该方向边界。 - 颜色选择导致面板重绘后,重新确认同一商品页和规格面板,再恢复规格区域并选择尺码。 - 根据证据决定是否移除默认规则固定 `up×2`;不得在证据出现前删除。 #### C. 若主要为 `click_failed` 只修复对应 fresh-node 重定位或最近可点击规格卡片选择问题;不得用坐标盲点、兄弟节点、相似文本或更宽松匹配兜底。 阶段 B 只实施真实阶段需要的最小项;未实施项及原因写回工单。 ## 验收标准 ### 阶段 A 退出条件 - [ ] `TaskPayload` / Android payload 已新增并正确解析 `specResolutionAllowed`,资格矩阵覆盖 `syb_order`、`stock/direct_select`、已固化决策和普通就地重试。 - [ ] 普通就地重试保留 `SpecDecisionRequestID`、目标规格、已映射规格和规格决策快照,探测资格不恢复。 - [ ] 规格失败按五态及允许的稳定子原因上报;点击动作失败与点击成功但选中未确认可明确区分。 - [ ] 只有 `target_not_visible && specResolutionAllowed=true` 才返回 `spec_probe_completed`;旧 Agent 重复探测仍 fail-closed,并使用明确的重复探测拒绝原因。 - [ ] 服务端保留普通 failed 的真实根因,不再统一覆盖为“再次执行仍未能……”。 - [ ] 旧快照含安全尾价时只在执行边界规范化比较,历史快照字段保持原样;规范化为空、残留货币或发生碰撞时安全失败。 - [ ] Android 与 Server 对相同规范化、碰撞、资格和失败阶段样本的单元/契约测试通过,APK 与 Server 构建通过。 - [ ] CG30 使用无地址、无订单动作的安全 rehearsal 取得明确五态结果或证明现有行为已可完成复核;证据已回写工单。 - [ ] 阶段 A 未重试 task 30 live 任务,未修改地址、未创建订单、未支付。 ### 阶段 B 及整单最终验收 - [ ] 阶段 B 的实际改动严格来自阶段 A 的 CG30 证据,最小修复范围已经用户确认;未实施项及原因已记录。 - [ ] CG30 / PDD 8.22.0 的安全 rehearsal 中,精确映射 `黑色 / 3XL 建议:150斤-180斤` 完成颜色、尺码与最终摘要复核,并在 `verifyOrderSummary` 后停止。 - [ ] 父链证据只限最近可点击规格卡片,不越过维度、滚动或面板容器。 - [ ] 摘要只按独立规格段或独立 token 严格相等确认,代码中不以 `contains` 判断完整规格已选。 - [ ] `XL` 不匹配 `2XL/3XL`;两个候选共享主 token 时短摘要证据失败。 - [ ] 若修改滚动行为,容器内到顶/到底、面板重绘后容器重定位和可见签名连续稳定均通过测试。 - [ ] 诊断不包含规格原文、坐标、控件树、截图、账号、地址、订单或支付数据。 - [ ] Wiki `Android-Agent-API-Contract` 已记录 `specResolutionAllowed`、资格矩阵、稳定失败阶段和重复探测拒绝语义,在线回读 revision 后完成一次 `sync` 和一次 `sync --check`。 - [ ] 未修改地址、未创建订单、未支付;任何 live 行为仍需独立人工授权。 ## 必测场景 - 文本节点自身选中;仅最近可点击规格卡片选中;面板/列表祖先选中但规格卡片未选中,后者不得误判。 - 摘要为独立完整目标;`亮黑色` 不得证明 `黑色`;摘要无法可靠分段时失败。 - 同维度存在 `XL/2XL/3XL`;两个完整候选共享主 token `XL` 时失败。 - 目标不存在、严格等价候选歧义、安全点击卡片缺失、fresh 节点失效、点击返回 false、点击成功但无选中证据分别进入正确阶段。 - 探测资格为 true/false、首次探测固化后再次领取、旧 Agent 重复探测。 - 旧目标含安全尾价;中间货币符号、规范化为空或规范化碰撞时失败。 - 若阶段 B 修改滚动:容器内到顶/到底、面板重绘后容器重定位、可见签名连续两次稳定。 ## 风险与安全门禁 - 这是采购动作、安全判据与共享契约修改;实施前必须由用户确认本次修订方案。 - 阶段 B 不得先于阶段 A 的 CG30 安全 rehearsal 证据。 - 不得通过放宽相等判断提高成功率;证据不足必须失败。 - 安全尾价规范化可能使多个原始候选折叠为同一值;该情况必须从偶然成功收敛为明确失败,禁止自动选择任一候选。实施前只读统计当前任务/商品影响范围,Android 与 Server 使用同一组 Unicode 空白、尾价、残留货币和碰撞样本验证,并把统计与结果回写工单。 - 真机验证固定为无地址、无订单动作的 rehearsal;任何 live 重试、修改地址或创建待付款订单必须另行取得人工授权。 - 永久禁止支付。 ## 文档影响 **有长期文档影响。** 本单新增 `specResolutionAllowed`、稳定规格失败阶段以及重复探测拒绝语义,必须更新 Wiki `Android-Agent-API-Contract`;在线回读 revision 后执行一次 `python dev_scripts/harness.py sync` 和一次 `sync --check`,并把页面 revision 回写工单。 ## 相邻问题(不在本单范围) Android 侧繁简等价规格文本比较另建工单评估,本单不处理。 ## 状态 进行中(2026-08-31 用户已确认,先执行阶段 A;阶段 B 仍以阶段 A 的 CG30 证据和再次确认作为门禁)。
Author
Owner

方案复核(2026-08-31,Claude Code 只读核验,基线 4e05048)

Gitea MCP 未向当前会话暴露,按仓库规则回退 Gitea API 追加本评论;凭据未写入工单、代码或日志。

一、引用代码事实已逐条核验,均属实

  • PurchaseRehearsalExecutor.kt:103:只要规则动作含 probeSpecs,任何 PURCHASE_SPEC_NOT_MATCHED 都被 probeOutcome() 覆盖,真实失败阶段丢失。属实。
  • purchase/lifecycle.go:335-343:SpecDecisionRequestID != nil 时第二次 spec_probe_completed 写死为 PURCHASE_SPEC_NOT_MATCHED / 再次执行仍未能精确选择商品规格,请检查商品规格,覆盖 Agent 根因。属实,与 task 30 现象一致。
  • 目标侧未规范化:PddProductDetailCollector.kt:273 对页面 size 值调用 SpecValueNormalizer.normalizeSize,而 selectSpecs(PurchaseRehearsalExecutor.kt:280)直接使用 input.mappedSize 原文参与定位与比较,两侧语义确实不一致。属实。
  • 选中复核证据不足:isExactSpecSelected 只检查候选节点自身 selected/checked,兜底 summarySelectionMatches 依赖同维度可见候选主 token 唯一,候选离屏或选中态挂在祖先时证据确实可能不足。属实。

二、方案方向认可

  • 探测资格由服务端 specResolutionAllowed 显式下发,而非让 Android 从 phase 或映射是否非空推导,符合「规格匹配决策权在服务端」;对旧 Agent 保持 fail-closed 并改用稳定的重复探测拒绝原因,处理得当。
  • 阶段 A 先恢复真实失败阶段、不提前删除 up×2、不提前改造滚动,避免破坏现场导致原根因不可判定,取舍正确。
  • 明确不移植参考实现的分隔符子串匹配、无限父链上溯、XML 落盘与繁简转换,符合永久规则。
  • 目标侧规范化只在执行边界应用、历史快照保持不可变,边界清晰。

三、建议修订的四点

  1. 「探测资格固化后永久为 false」与重置流程存在冲突(功能性缺口)。
    全仓 SpecDecisionRequestID 仅在 lifecycle.go:455 写入,purchase/reset.go 未清除该字段(其重置逻辑只在 reset.go:134 判断 SpecSource == "unresolved")。按当前措辞,任务一旦固化过一次探测决策,重置后也将永远无法再次探测。需在工单明确二选一:重置时清除 SpecDecisionRequestID 并恢复资格;或保持不清除并写明理由与对运维的影响。

  2. 验收标准混淆了阶段 A 与阶段 B(流程性缺口)。
    首条验收(CG30 rehearsal 完整完成颜色、尺码与摘要复核并停在 verifyOrderSummary)在阶段 A 明确「不改滑动行为」的前提下不可能达成。建议按阶段拆分验收清单,否则阶段 A 无法独立收敛到待验收。

  3. 阶段 A 的定位建议调整为「契约修复」而非「诊断阶段」。
    五态枚举、specResolutionAllowed、服务端保留根因以及 Android Agent API 契约与 Wiki 更新,是目标 1、2 本身所必需,并非仅为取证。按「诊断」定位容易在后续放松测试与验收要求。

  4. 规范化冲突安全失败的回归面需在风险章节显式列出。
    「多个原始候选折叠为同一值时安全失败」会把当前偶然成功的任务转为明确失败。这一取舍本身正确(宁失败不猜测),但应在风险与安全门禁中写明影响范围与评估方式,避免验收时被误判为新引入缺陷。

四、结论

方案整体合理,具备可实施性。建议在修订上述第 1、2 点(真实功能性/流程性缺口)后再由用户确认;第 3、4 点为表述与风险记录完善项。本次为只读核验,未修改任何代码、任务或快照。

## 方案复核(2026-08-31,Claude Code 只读核验,基线 `4e05048`) > Gitea MCP 未向当前会话暴露,按仓库规则回退 Gitea API 追加本评论;凭据未写入工单、代码或日志。 ### 一、引用代码事实已逐条核验,均属实 - `PurchaseRehearsalExecutor.kt:103`:只要规则动作含 `probeSpecs`,任何 `PURCHASE_SPEC_NOT_MATCHED` 都被 `probeOutcome()` 覆盖,真实失败阶段丢失。属实。 - `purchase/lifecycle.go:335-343`:`SpecDecisionRequestID != nil` 时第二次 `spec_probe_completed` 写死为 `PURCHASE_SPEC_NOT_MATCHED / 再次执行仍未能精确选择商品规格,请检查商品规格`,覆盖 Agent 根因。属实,与 task 30 现象一致。 - 目标侧未规范化:`PddProductDetailCollector.kt:273` 对页面 size 值调用 `SpecValueNormalizer.normalizeSize`,而 `selectSpecs`(`PurchaseRehearsalExecutor.kt:280`)直接使用 `input.mappedSize` 原文参与定位与比较,两侧语义确实不一致。属实。 - 选中复核证据不足:`isExactSpecSelected` 只检查候选节点自身 `selected/checked`,兜底 `summarySelectionMatches` 依赖同维度可见候选主 token 唯一,候选离屏或选中态挂在祖先时证据确实可能不足。属实。 ### 二、方案方向认可 - 探测资格由服务端 `specResolutionAllowed` 显式下发,而非让 Android 从 `phase` 或映射是否非空推导,符合「规格匹配决策权在服务端」;对旧 Agent 保持 fail-closed 并改用稳定的重复探测拒绝原因,处理得当。 - 阶段 A 先恢复真实失败阶段、不提前删除 `up×2`、不提前改造滚动,避免破坏现场导致原根因不可判定,取舍正确。 - 明确不移植参考实现的分隔符子串匹配、无限父链上溯、XML 落盘与繁简转换,符合永久规则。 - 目标侧规范化只在执行边界应用、历史快照保持不可变,边界清晰。 ### 三、建议修订的四点 1. **「探测资格固化后永久为 false」与重置流程存在冲突(功能性缺口)。** 全仓 `SpecDecisionRequestID` 仅在 `lifecycle.go:455` 写入,`purchase/reset.go` 未清除该字段(其重置逻辑只在 `reset.go:134` 判断 `SpecSource == "unresolved"`)。按当前措辞,任务一旦固化过一次探测决策,重置后也将永远无法再次探测。需在工单明确二选一:重置时清除 `SpecDecisionRequestID` 并恢复资格;或保持不清除并写明理由与对运维的影响。 2. **验收标准混淆了阶段 A 与阶段 B(流程性缺口)。** 首条验收(CG30 rehearsal 完整完成颜色、尺码与摘要复核并停在 `verifyOrderSummary`)在阶段 A 明确「不改滑动行为」的前提下不可能达成。建议按阶段拆分验收清单,否则阶段 A 无法独立收敛到待验收。 3. **阶段 A 的定位建议调整为「契约修复」而非「诊断阶段」。** 五态枚举、`specResolutionAllowed`、服务端保留根因以及 Android Agent API 契约与 Wiki 更新,是目标 1、2 本身所必需,并非仅为取证。按「诊断」定位容易在后续放松测试与验收要求。 4. **规范化冲突安全失败的回归面需在风险章节显式列出。** 「多个原始候选折叠为同一值时安全失败」会把当前偶然成功的任务转为明确失败。这一取舍本身正确(宁失败不猜测),但应在风险与安全门禁中写明影响范围与评估方式,避免验收时被误判为新引入缺陷。 ### 四、结论 方案整体合理,具备可实施性。建议在修订上述第 1、2 点(真实功能性/流程性缺口)后再由用户确认;第 3、4 点为表述与风险记录完善项。本次为只读核验,未修改任何代码、任务或快照。
Author
Owner

开始执行 #164 阶段 A(用户于 2026-08-31 明确确认第二次修订方案)。

基线:4e05048。当前工作区存在与本单无关的 Web E2E、prototypes/130/ 及本地临时文件改动,将全部保留且不纳入本单提交。

本轮范围:共享契约 specResolutionAllowed、服务端资格矩阵与失败根因保留、Android 五态/稳定子原因和目标侧尾价规范化、对应测试、Wiki 契约同步,以及 CG30 无地址/无订单动作的安全 rehearsal。阶段 A 不删除规则 up×2、不改造滚动行为;不重试 task 30 live 任务,不修改地址、不创建订单、不支付。若仍需阶段 B,将先回写真实失败阶段和最小修复项并等待再次确认。

当前会话未暴露 Gitea MCP,按仓库规则回退项目安全配置与 Gitea API;凭据未写入工单、代码或日志。

开始执行 #164 阶段 A(用户于 2026-08-31 明确确认第二次修订方案)。 基线:`4e05048`。当前工作区存在与本单无关的 Web E2E、`prototypes/130/` 及本地临时文件改动,将全部保留且不纳入本单提交。 本轮范围:共享契约 `specResolutionAllowed`、服务端资格矩阵与失败根因保留、Android 五态/稳定子原因和目标侧尾价规范化、对应测试、Wiki 契约同步,以及 CG30 无地址/无订单动作的安全 rehearsal。阶段 A 不删除规则 `up×2`、不改造滚动行为;不重试 task 30 live 任务,不修改地址、不创建订单、不支付。若仍需阶段 B,将先回写真实失败阶段和最小修复项并等待再次确认。 当前会话未暴露 Gitea MCP,按仓库规则回退项目安全配置与 Gitea API;凭据未写入工单、代码或日志。
Author
Owner

阶段 A 实施与首次 CG30 安全 rehearsal(2026-08-31)

Gitea MCP 仍未向当前会话暴露,本次继续按工单既有记录回退 Gitea API;凭据未进入代码、日志、工单或 Wiki。

已提交并推送 866aea1(fix(goauto): preserve exact spec failure evidence (#164)):

  • Server 下发 specResolutionAllowed,按 syb_order / stock、规则能力、direct_select 与已固化 SpecDecisionRequestID fail-closed;普通就地重试不恢复资格。
  • Android 规格失败收敛为五个稳定阶段;PURCHASE_SPEC_CLICK_FAILED 使用稳定子原因。只有 PURCHASE_SPEC_TARGET_NOT_VISIBLE && specResolutionAllowed=true 才允许返回规格探测。
  • 目标侧复用 #160 安全尾价规范化;空值、残留货币符号与规范化碰撞安全失败,历史快照不改写。
  • 旧 Agent 重复探测改为 PURCHASE_SPEC_REPROBE_REJECTED,服务端保留第一次决策。
  • 阶段 A 未修改既有 up×2 或有界搜索行为。

验证:

  • go test ./...:通过。
  • go build ./...:通过。
  • gradlew testDebugUnitTest assembleDebug --rerun-tasks:通过。
  • Wiki Android-Agent-API-Contract 已在线更新并回读 revision 52119b8626496af10f232fb663595779427f37f0;随后已执行一次 harness.py sync 和一次 sync --check。
  • CG30 已安装 Agent 0.9.30(versionCode 43),PDD 8.22.0。

首次真机任务为 CG-31:executionMode=rehearsal,规则不含 updateShippingAddress、createOrder、readOrderResult,通过隔离的 866aea1 服务实例执行;未重试 task 30 live。CG-31 在进入 PDD 操作前以 ACCESSIBILITY_NOT_READY / GoAuto 无障碍服务未开启 安全失败,因此尚未取得五态规格证据,不能视为阶段 A 退出,也没有进入阶段 B。

现场已恢复 CG30 原服务器地址并移除临时 ADB 反向端口、隔离服务和临时 worktree。未修改地址、未创建订单、未支付。

当前阻塞:开启 GoAuto 无障碍服务属于权限变更,按仓库门禁等待用户明确确认。确认后重新创建一个同等安全 rehearsal;若命中规格五态,再按工单决定是否提出阶段 B 最小修复并再次等待确认。

## 阶段 A 实施与首次 CG30 安全 rehearsal(2026-08-31) Gitea MCP 仍未向当前会话暴露,本次继续按工单既有记录回退 Gitea API;凭据未进入代码、日志、工单或 Wiki。 已提交并推送 `866aea1`(`fix(goauto): preserve exact spec failure evidence (#164)`): - Server 下发 `specResolutionAllowed`,按 `syb_order` / `stock`、规则能力、`direct_select` 与已固化 `SpecDecisionRequestID` fail-closed;普通就地重试不恢复资格。 - Android 规格失败收敛为五个稳定阶段;`PURCHASE_SPEC_CLICK_FAILED` 使用稳定子原因。只有 `PURCHASE_SPEC_TARGET_NOT_VISIBLE && specResolutionAllowed=true` 才允许返回规格探测。 - 目标侧复用 #160 安全尾价规范化;空值、残留货币符号与规范化碰撞安全失败,历史快照不改写。 - 旧 Agent 重复探测改为 `PURCHASE_SPEC_REPROBE_REJECTED`,服务端保留第一次决策。 - 阶段 A 未修改既有 `up×2` 或有界搜索行为。 验证: - `go test ./...`:通过。 - `go build ./...`:通过。 - `gradlew testDebugUnitTest assembleDebug --rerun-tasks`:通过。 - Wiki `Android-Agent-API-Contract` 已在线更新并回读 revision `52119b8626496af10f232fb663595779427f37f0`;随后已执行一次 `harness.py sync` 和一次 `sync --check`。 - CG30 已安装 Agent `0.9.30`(versionCode 43),PDD `8.22.0`。 首次真机任务为 CG-31:`executionMode=rehearsal`,规则不含 `updateShippingAddress`、`createOrder`、`readOrderResult`,通过隔离的 `866aea1` 服务实例执行;未重试 task 30 live。CG-31 在进入 PDD 操作前以 `ACCESSIBILITY_NOT_READY / GoAuto 无障碍服务未开启` 安全失败,因此尚未取得五态规格证据,不能视为阶段 A 退出,也没有进入阶段 B。 现场已恢复 CG30 原服务器地址并移除临时 ADB 反向端口、隔离服务和临时 worktree。未修改地址、未创建订单、未支付。 当前阻塞:开启 GoAuto 无障碍服务属于权限变更,按仓库门禁等待用户明确确认。确认后重新创建一个同等安全 rehearsal;若命中规格五态,再按工单决定是否提出阶段 B 最小修复并再次等待确认。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#164