fix(android): 规格复核前移到改地址前;改地址后不核对规格和数量,只拦「选择…后,提交订单」(#374 后续) #376

Open
opened 2026-10-09 16:17:27 +08:00 by ila · 4 comments
Owner

基本信息

  • 类型:缺陷(Android 采购:规格复核在规格已选对时误拦;规格丢失要到改完地址后才发现;会点击「选择…后,提交订单」这种并非真正提交的按钮)。
  • 风险等级:高。两处复核都在创建订单之前,本单明确放宽了改地址后的检查。实施、装机和真机验证都需要用户另行确认。
  • 状态:正文 v3(2026-10-09),已实施、测试并推送工单分支,已覆盖安装指定手机,待真机业务验收;未合并 main、未发布服务端。v1(剥离摘要营销标签、滑动取证)和 v2(改地址后检查摘要未选提示、保留数量核对)都已被本版替代。本版整合了 Codex 对 v2 的审核意见(SynapBus #129/#130,评论 9098)、Codex 对 v3 的补充(#133/#134)和 Claude Code 的复核意见(评论 9101)。
  • 修订记录:2026-10-09 16:51 Codex 补充真机证据和按钮文字来源;该次更新误把方案 0 正则结尾替换成了一段重复正文,16:58 已修复(与原文逐字核对一致);之后 Claude Code 补充方案 0 的拼接规则、失败现场结构核对和两条验收。
  • 来源:2026-10-09,用户在 192.168.0.9:39459 安装合入 #373、#374 的 APK(Agent 0.9.69-373-fix1)后,重购最后一批 7 个采购任务,要求分析失败原因。随后经过讨论和逐题问答确认:
    • 「如果进入了地址面板修改了地址,回到规格面板,我还是坚持不用再去符合是否选中目标颜色尺码数量了」。
    • 「grill me:我还是保留进入规格面板选中了目标颜色尺码数量后,从地址面板回来到规格面板时不需要再次核对当前选中的颜色尺码数量是什么.或者我们每次采购时进入pdd app商品页时先清除已选中的颜色尺码……如果没有选中是无法下单的,直接下单失败.后续再去分析失败原因」。
    • 问答结论见下表。用户最后要求:「重写#376第三版,然后通知codex复核」。
  • 关联:#374(前置,已合入)、#373。

用户确认的决定(2026-10-09 问答)

题 问题 决定 用户回答
1 规格丢失时「直接下单失败」要哪种失败 点提交前读提交按钮文字,遇到「选择…后,提交订单」就不点,任务按普通失败处理,重购继续 「A」
2 改地址回来后是否核对数量 不核对,接受数量可能不对的风险 「B.」
3 进入商品页后是否先清除已选规格 不清除,现有选规格方式不变 「A」
4 不核对之后如何事后分析 点提交前把屏幕状态记入本地最终证据,只记录不拦截;原 quantity 字段改为目标数量 「A」
5 改地址前的复核是否加严 加严 「A,为什么会"省一次改地址"呢」(已解释)
6 改地址后是否保留价格、地址、提交按钮唯一检查 三项都保留 「A」

已核验事实

线上数据与失败现场(只读,2026-10-09)

失败现场快照 2、10~13 只在本机解析规格面板文字,地址类文字已过滤,文件用完已删除。

任务 下单前复核结果(#374) 现场 判断
2129(attempt 4182) dimension=size;stage=missing_proof;summaryPresent=1 颜色、尺码都选对了;尺码选项和标题已滑出可视区;摘要为 已选: #[新品闪购*夏日大卖]桔色 XL [建议110-120斤] 误拦
2128(attempt 4183) dimension=color;stage=missing_proof;summaryPresent=0 颜色、尺码都选对了,且都可见;「颜色分类」标题已滑出可视区;摘要位置显示 #快要抢光#[纯白]RW圆领 3XL码[145-165斤] 误拦
2130(attempt 4181;11:47 的 attempt 4122 相同) dimension=color;stage=missing_proof;summaryPresent=0 摘要位置显示「请选择: 颜色分类 尺码」;提交按钮为「选择颜色分类及尺码后,提交订单」;没有任何选中项 拦得对:规格丢失
2131(attempt 4180) 在选规格时失败,PURCHASE_SPEC_SELECTION_UNCONFIRMED 摘要位置显示「请选择: 尺码」;提交按钮为「选择尺码后,提交订单」 不在本单范围
  • 2130(黑色 + L)6 次走到下单前复核,6 次都失败。同一商品 982178566127 的 2129(桔色 + XL)改完地址后规格仍然选中。这只能说明规格丢失不是每次改地址都会发生。规格丢在哪一步尚无证据确认,不能归因于地址修改,「黑色 + L」是否售罄也未核实(2026-09-28 采集任务 1520 时有货)。手机 logcat 已被覆盖。
  • 历史上「创建订单前数量复核失败」(PURCHASE_QUANTITY_MISMATCH)共 13 次,全部是数量 ≥ 2 的任务。数量 ≥ 2 的任务走到下单前或已完成的约 110 次,数量 = 1 的约 1570 次,后者从未出现。推断是改地址后 PDD 把数量重置了,但未证实。

补充真机文字证据(Codex 只读,2026-10-09)

用户保留未选中颜色、尺码的现场后,Codex 在指定测试手机上只读获取当前无障碍结构(PDD 包名 com.xunmeng.pinduoduo)。未点击、未滑动、未触发任务,原始树仅在内存解析,未落盘;以下仅记录不含个人信息的提示和结构:

位置 实际文字 节点证据
面板上方摘要 请选择: 颜色分类 尺码 单个完整 TextView;clickable=false、enabled=true;无子节点
面板底部提示 选择颜色分类及尺码后,提交订单 单个完整 TextView;clickable=false、enabled=true;无子节点,直接父节点也不可点击
  • 本次现场不存在提示拆成多个文字节点的情况;底部提示可被 v3 的完整文字规则匹配。
  • 文字节点的 enabled=true 不能证明规格已选全或可以创建订单;文字节点不可点击也不能据此排除它所属的提交按钮区域。实际点击目标与所属可点击区域仍按既有结构定位。
  • 此证据仅确认这一屏的文字与结构,不证明 #376 已实现、采购流程通过或其他布局全部覆盖。“拆分文字节点”仍作为合成结构回归用例,不当作本次失败根因。

失败现场结构核对(Claude Code 只读,2026-10-09,快照 11 / attempt 4181)

本机解析后已删除,只记录结构:

  • 面板容器内最下方的可点击节点是底部横条 FrameLayout(bounds [0,2159][1080,2306])。按 finalSubmitTargets 的规则,它就是被选中的提交行 row。
  • 「选择颜色分类及尺码后,提交订单」是一个 TextView,层级为 TextView → 不可点击的 LinearLayout → 上述 FrameLayout。它的最近可点击祖先就是 row,而且它是 row 内唯一带文字的节点。
  • 结论:在这个真实布局下,只读取 row 内文字的规则能读到完整提示,和 Codex 的真机观察(文字节点的直接父节点不可点击)一致。

代码事实(origin/main 3ee8dfc0aa93ef9020786244cce29c487631ddbe)

  • 执行顺序是 SELECT_SPEC → SET_QUANTITY → VERIFY_UNIT_PRICE → VERIFY_ORDER_SUMMARY → UPDATE_SHIPPING_ADDRESS → CREATE_ORDER(PurchaseRehearsalExecutor.kt:140-165),某一步失败后,后面的步骤都不执行。
  • CREATE_ORDER 依次执行 finalConfirmation → beforeOrderSubmit(evidence) → irreversibleStarted = true → submitOrderOnce(:161-178)。
    • beforeOrderSubmit(AgentForegroundService.kt:865-878)先在本地写 markOrderSubmitStarted(含 final_confirmation_json),再调用服务端 markPurchaseOrderSubmitStarted。
    • 此后任何异常都会被转成 order_result_unknown,现有 submitOrderOnce 在点击前失败的 PURCHASE_SUBMIT_TARGET_AMBIGUOUS 也是这样。
    • final_confirmation_json 只存在手机本地(PurchaseTaskStore.kt:130-139),不上传服务端;代码中没有任何地方解析它。其中 quantity 字段取自下发的目标数量(FinalConfirmationEvidence.quantity = input.quantity)。
  • 选规格(selectExactSpecWithRetry、isExactSpecSelected,:594-693):目标已经选中就不点;否则点击目标,点击后必须读到目标处于选中状态,或者摘要匹配,否则失败。
  • 改地址前的复核有漏洞:verifySummary(:1123)→ verifyExactSpecSelection(:751)。
    • 没有「已选」摘要时(selectedSummary == null,例如面板显示的是「请选择: …」),只要选规格时记录过证明,就直接判为通过(attempt_selection_state),即使目标选项就在屏幕上且没有选中。
    • 摘要匹配、但选项不可见时,同样沿用历史证明(attempt_selection_proof)。
  • 下单前复核:finalConfirmation(PurchaseLiveAutomation.kt:314)依次检查地址、唯一提交按钮、规格(PurchaseFinalSpecVerifier.verify,#374,要求每个维度都有可见证据或摘要整段相等,否则 missing_proof)、价格、数量。
  • finalSubmitTargets(PurchaseLiveAutomation.kt:882)主要按结构定位:在已识别面板范围内选择底部可点击行,再返回该行内符合条件的带文字节点供 clickFresh 重定位并向上找到可点击祖先;既有支付类文字排除保持不变。FINAL_SUBMIT_MARKERS / legacyMarker 只是诊断信号,不是定位放行条件。因此「选择颜色分类及尺码后,提交订单」仍可能被结构定位为提交目标,须另加未选提示检查;不能描述为靠「提交订单」文字定位。

目标

  1. 规格是否选对,在改地址之前严格核对,不再沿用历史记录来掩盖当前的未选状态。
  2. 改地址之后不再核对颜色、尺码、数量,只确认提交按钮不是「选择…后,提交订单」;价格、地址、提交按钮唯一的检查照旧。
  3. 规格丢失时不点击假提交按钮。在最终复核阶段发现时按普通失败处理,重购继续。
  4. 点提交前记录屏幕状态,便于事后分析。

非目标

  • 不重新选规格,不在进入商品页时清除已选规格。
  • 改地址后不比较颜色、尺码的值,不核对数量。
  • 不在规格列表中滑动取证,不剥离摘要营销标签。
  • 不移动提交边界(beforeOrderSubmit)的位置,不改本地存储和服务端边界协议,不上传 final_confirmation_json。
  • 不处理 2131 的点击后未选中、2127 的从微信恢复超时,不查 2130 的组合是否售罄。
  • 不改服务端、API、数据库和 Web。不实现任何支付动作。

方案

0. 共用判断(新函数,只在规格复核中使用)

  • 按钮未选提示:只检查 finalSubmitTargets 唯一目标所属的实际提交按钮区域,区域必须可见且位于当前面板内;沿用既有底部行与最近可点击祖先关系,不改变点击目标选择。读取该区域当前可见的提示文字,而不是只依赖返回的单个文字节点或 enabled 属性。完整单节点提示直接检查;若同一按钮的提示拆分到多个文字节点,按明确的阅读顺序组合属于同一按钮的文字片段,不重复叠加父子节点相同文字,不拼入其他按钮、嵌套独立可点击子按钮、规格列表、面板摘要或不可见旧节点。不扩大到全屏搜索。去掉全部空白后,必须从头到尾完整匹配:^(选择|選擇).+(后|後)[,,](提交订单|提交訂單)$。不使用「包含某个词」的判断。此文字来源规则在改地址前、finalConfirmation 与 submitOrderOnce 的提示检测中共用;不新增规格值或数量复核。
    • 具体拼接规则:
      1. 以 finalSubmitTargets 已选出的行 row 为范围,不只看返回的 chosen;
      2. 只取 row 子树中可见、自身有文字、子孙都没有文字的节点;
      3. 这些节点的最近可点击祖先必须是 row,与现有 leafCandidates 的条件相同,从而排除嵌套的独立可点击子按钮;
      4. 按 bounds.top、再按 bounds.left 排序后直接拼接。
    • 不复用现有的 rowSubtreeLabels:它把 row.label 和全部子孙 label 拼在一起,在 label 会上传给父节点的布局下会重复。
    • 建议 finalSubmitTargets 一并返回 row、chosen 和拼接后的文字,三处调用共用;点击目标仍是 chosen,行的选择、唯一性和支付排除逻辑不变。实施时选最小改法。
  • 摘要未选提示:在当前可见的规格面板内(沿用 #374 的面板范围),处在摘要位置、可见、不可点击的文字。去掉全部空白后以「请选择」或「請選擇」开头,后面可以跟全角或半角冒号。不在全屏搜索。
  • 目标可见但未选中:某个维度中,与目标完全相等(normalizeFinalConfirmation)的选项可见、可选,且未选中(selected、checked 都为 false,沿用解析器的父子聚合);同维度没有其他选中项;面板内也没有「已选」摘要。

1. 改地址前的复核(verifySummary,加严,第 5 题)

  • 判断每个目标维度之前,以及每次重新定位滑动之后,都先检查摘要未选提示和按钮未选提示(按钮提示只在当前面板识别出唯一提交按钮时检查)。出现任一提示就失败,原因 selection_prompt。
  • attempt_selection_state 和 attempt_selection_proof 这两条沿用历史证明的路径,只在当前屏幕出现目标可见但未选中时改为失败,原因 target_visible_unselected。目标选项不可见时仍然沿用历史证明,这两条路径不是全部取消。
  • 其余路径不变:看到目标选中、摘要匹配且候选唯一。verifySummary 中现有的数量和价格检查也不变。
  • 错误码仍为 PURCHASE_SPEC_SELECTION_UNCONFIRMED,诊断里的 reason 使用新值。失败发生在改地址之前,不执行改地址。

2. 改地址后的下单前复核(finalConfirmation,放宽,第 1、2、6 题)

  • 保留:地址复核、提交按钮唯一、价格在区间内,判断内容不变。
  • 新增:唯一提交按钮出现按钮未选提示时,报 PURCHASE_SPEC_NOT_MATCHED,详情 finalSpec;stage=selection_prompt,不含页面文字。这一步在 beforeOrderSubmit 之前,所以是普通失败:不写本地和服务端的提交边界,不点击,任务记为 failed,重购继续下一个任务。
  • 移除:PurchaseFinalSpecVerifier 的全部规格判断(missing_proof、摘要整段相等、selected_conflict、candidate_collision、unavailable、summary_conflict、composition_ambiguity),以及数量核对(PURCHASE_QUANTITY_MISMATCH)。改地址后不检查摘要未选提示,只记录(见方案 4)。
  • 只用当前这一张截图,不滑动、不点击。

3. 点击前兜底(submitOrderOnce)

  • 点击前截图时,如果唯一提交按钮出现按钮未选提示,就不点击并抛出异常。
  • 此时提交边界已经写入,按现有逻辑结果如实保留为 order_result_unknown,边界只写这一次。要把这个零点击分支变成确定的失败,必须扩大到本地存储和服务端边界协议,不在本单范围;需要时另行建单并确认。
  • 这个分支只在「最终复核通过、下一次截图才出现提示」时触发,主防线是方案 2。

4. 只记录、不拦截的屏幕状态(第 4 题)

  • FinalConfirmationEvidence 新增:
    • observedQuantity:唯一可见可用数量输入框中的数字;如果不是恰好一个,记为空;
    • selectedSummaryPresent:面板内是否有「已选」摘要;
    • summaryPromptPresent:面板内是否有摘要未选提示。
  • 写入本地 final_confirmation_json 时,原 quantity 键改为 targetQuantity,并增加上面三项。新增字段只有数字和布尔值,不含页面文字和个人信息。
  • 只记录,不参与任何判断;不上传服务端。事后分析需读取手机本地数据库,上传另行建单。

用本批现场对照

任务 改地址前(方案 1) 改地址后(方案 2、3)
2128 不变 放行(按钮是正常的「提交订单」)
2129 不变 放行
2130 规格如果在这之前就丢了:以 selection_prompt 或 target_visible_unselected 失败,不执行改地址 规格如果到这里才丢:以 selection_prompt 普通失败,不点击、不写边界

子项目影响、依赖与并行

  • Android:
    • PurchaseRehearsalExecutor.kt(verifySummary / verifyExactSpecSelection);
    • PurchaseLiveAutomation.kt(finalConfirmation、submitOrderOnce、FinalConfirmationEvidence);
    • PurchaseFinalSpecVerifier.kt(改为只做按钮提示判断,或者删除后由新函数替代,实施时选最小改法);
    • AgentForegroundService.kt(beforeOrderSubmit 中 JSON 键名和新增字段);
    • 必要时 PddProductDetailCollector.kt(只读取面板内的摘要提示,不改现有解析行为);
    • 以及对应测试。
  • Server/Web:无。数据库、API:无。
  • 依赖 #374(已合入)。不与其他修改采购执行器的工单并行。

设计证据

非 UI 改动,无需原型;以本正文为准。

验收标准

改地址前(方案 1):

  • 2130 的脱敏结构(「请选择: 颜色分类 尺码」+「选择颜色分类及尺码后,提交订单」,没有选中项)→ 失败,reason=selection_prompt,没有执行改地址。
  • 只有摘要提示 → 失败;只有按钮提示 → 失败。
  • 没有提示、没有「已选」摘要、目标尺码 L 可见但未选中、有历史证明 → 失败,target_visible_unselected(原来会以 attempt_selection_state 通过)。
  • 目标选项不可见、没有摘要、没有提示、有历史证明 → 仍然通过(行为不变)。
  • 不暴露选中属性的布局:有「已选」摘要时不受影响;没有摘要、也没有选中属性时会失败,按风险第 2 条记录为已知行为。

改地址后(方案 2):

  • 2128、2129 的脱敏结构(正常「提交订单」按钮)→ 放行。
  • 2130 的脱敏结构 → PURCHASE_SPEC_NOT_MATCHED(stage=selection_prompt)。执行器层面验证:beforeOrderSubmit 没有被调用,本地没有 order_submit_started,没有点击,任务记为 failed。
  • 可见选中项不等于目标、没有按钮提示 → 放行(按用户决定,作为已知行为保留用例)。
  • 数量输入框不等于目标数量 → 放行(按用户决定,作为已知行为保留用例)。
  • 地址复核失败、提交按钮不唯一、价格超出区间 → 照旧失败,相关测试不删除。
  • 下单前复核不调用任何点击或滑动。

点击前兜底(方案 3):

  • 最终复核通过,submitOrderOnce 截图时按钮出现提示 → 不点击;执行器结果为 order_result_unknown,提交边界只写一次。

提示识别正反例(方案 0):

  • 按上述真机脱敏结构:摘要与底部提示分别是完整单个 TextView,均 enabled=true,底部文字节点及直接父节点不可点击 → 仍通过既有结构关联其实际按钮区域并识别未选提示;不能因文字节点启用或不可点击而漏判。最终复核在边界前普通失败、不点击;点击前兜底保留既定 unknown 语义。
  • 合成拆分布局:同一个提交按钮区域内,选择颜色分类及尺码后, 和 提交订单 分处两个可见文字节点,返回的点击文字节点只含后一段 → 组合该按钮文字后能识别;父子重复标签不重复拼接。此项是其他布局的回归,不是本次现场事实。
  • 合成隔离反例:提示片段分属不同按钮、独立可点击子按钮或按钮区域外 → 不跨区域拼成未选提示;原有按钮定位、唯一性及支付排除检查不变。
  • 提示在面板外(例如商品详情页规格入口「请选择 颜色分类」)→ 不算提示。
  • 不可见的旧节点 → 不算提示。
  • 普通「提交订单」、「现在买,仅…」、「确认购买」按钮 → 不算提示。
  • 简体、繁体、全角逗号、半角逗号、带空格的形式 → 能识别;文字只是包含「提交订单」但不符合完整格式 → 不算提示。
  • 改地址前,当前面板类型不在 PURCHASE_CONFIRMATION_PANEL_TYPES 中(finalSubmitTargets 返回空)→ 只检查摘要提示,不因找不到按钮而报错。
  • finalConfirmation 中 finalSubmitTargets 返回空或不唯一 → 仍按现有逻辑报 PURCHASE_SUBMIT_TARGET_AMBIGUOUS,不受新规则影响。

屏幕状态记录(方案 4):

  • final_confirmation_json 中有 targetQuantity、observedQuantity、selectedSummaryPresent、summaryPromptPresent,原 quantity 键已经不存在;数量输入框不是恰好一个时,observedQuantity 为空;不含页面文字和个人信息。

回归:

  • PurchaseFinalSpecConfirmationTest 按新规则改写,在回写中逐条说明删除或改写的用例;verifySummary、地址、价格、提交按钮相关测试通过;Android 构建通过,如实记录。
  • 真机验证需要用户另行授权(正式采购可能真实下单);未执行时如实记录。

风险与回退

  1. 剩余风险:规格(用户已确认)。改地址后,如果 PDD 把规格换成了其他值,同时提交按钮仍然是正常的「提交订单」,就会下错规格。目前还没有观察到这种情况;改地址前的复核会严格核对。
  2. 剩余风险:数量(用户已确认,第 2 题 B)。改地址后数量如果被重置,会按错误数量下单。历史上数量 ≥ 2 的任务约每 8~9 次就有 1 次被原来的数量核对拦下,原因未证实。建议采购员付款前核对数量;observedQuantity 可以用来事后核查。
  3. 不暴露选中属性、也没有「已选」摘要的面板布局上,改地址前的 target_visible_unselected 可能误拦。这是偏安全的方向。
  4. 改地址前的复核加严后,部分任务会提前失败。这些任务原本也会在后面失败,只是失败得更早。
  5. 方案 3 的兜底分支仍会产生 order_result_unknown,需要人工核对,重购会停。只有在最终复核到点击之间页面发生变化时才会走到这里。
  6. 回退:恢复 #374 的下单前复核、数量核对和原来的 verifySummary;无数据迁移。final_confirmation_json 的键名变化只影响新写入的记录。

文档影响

  • 更新 Wiki Business-Rules-and-Glossary(采购执行):
    • 改地址前严格核对规格;
    • 改地址后只确认提交按钮不是「选择…后,提交订单」,并检查价格、地址、提交按钮唯一;
    • 不核对规格值和数量,以及由此带来的剩余风险;
    • 本地最终证据中的字段。
  • 先改线上 Wiki 并回读 revision,再执行一次 sync 和一次 sync --check。

备注

本单由 Claude Code 依据线上只读查询、失败现场快照(本机解析后已删除)、代码阅读、与用户的问答和 Codex 审核意见起草;不含账号、地址、Cookie 或 Token。

## 基本信息 - 类型:缺陷(Android 采购:规格复核在规格已选对时误拦;规格丢失要到改完地址后才发现;会点击「选择…后,提交订单」这种并非真正提交的按钮)。 - 风险等级:**高**。两处复核都在创建订单之前,本单明确**放宽**了改地址后的检查。实施、装机和真机验证都需要用户另行确认。 - 状态:**正文 v3(2026-10-09),已实施、测试并推送工单分支,已覆盖安装指定手机,待真机业务验收;未合并 main、未发布服务端**。v1(剥离摘要营销标签、滑动取证)和 v2(改地址后检查摘要未选提示、保留数量核对)都已被本版替代。本版整合了 Codex 对 v2 的审核意见(SynapBus #129/#130,评论 9098)、Codex 对 v3 的补充(#133/#134)和 Claude Code 的复核意见(评论 9101)。 - 修订记录:2026-10-09 16:51 Codex 补充真机证据和按钮文字来源;该次更新误把方案 0 正则结尾替换成了一段重复正文,16:58 已修复(与原文逐字核对一致);之后 Claude Code 补充方案 0 的拼接规则、失败现场结构核对和两条验收。 - 来源:2026-10-09,用户在 192.168.0.9:39459 安装合入 #373、#374 的 APK(Agent `0.9.69-373-fix1`)后,重购最后一批 7 个采购任务,要求分析失败原因。随后经过讨论和逐题问答确认: - 「如果进入了地址面板修改了地址,回到规格面板,我还是坚持不用再去符合是否选中目标颜色尺码数量了」。 - 「grill me:我还是保留进入规格面板选中了目标颜色尺码数量后,从地址面板回来到规格面板时不需要再次核对当前选中的颜色尺码数量是什么.或者我们每次采购时进入pdd app商品页时先清除已选中的颜色尺码……如果没有选中是无法下单的,直接下单失败.后续再去分析失败原因」。 - 问答结论见下表。用户最后要求:「重写#376第三版,然后通知codex复核」。 - 关联:#374(前置,已合入)、#373。 ## 用户确认的决定(2026-10-09 问答) | 题 | 问题 | 决定 | 用户回答 | |---|---|---|---| | 1 | 规格丢失时「直接下单失败」要哪种失败 | 点提交前读提交按钮文字,遇到「选择…后,提交订单」就不点,任务按普通失败处理,重购继续 | 「A」 | | 2 | 改地址回来后是否核对数量 | **不核对**,接受数量可能不对的风险 | 「B.」 | | 3 | 进入商品页后是否先清除已选规格 | 不清除,现有选规格方式不变 | 「A」 | | 4 | 不核对之后如何事后分析 | 点提交前把屏幕状态记入本地最终证据,只记录不拦截;原 `quantity` 字段改为目标数量 | 「A」 | | 5 | 改地址前的复核是否加严 | 加严 | 「A,为什么会"省一次改地址"呢」(已解释) | | 6 | 改地址后是否保留价格、地址、提交按钮唯一检查 | 三项都保留 | 「A」 | ## 已核验事实 ### 线上数据与失败现场(只读,2026-10-09) 失败现场快照 2、10~13 只在本机解析规格面板文字,地址类文字已过滤,文件用完已删除。 | 任务 | 下单前复核结果(#374) | 现场 | 判断 | |---|---|---|---| | 2129(attempt 4182) | `dimension=size;stage=missing_proof;summaryPresent=1` | 颜色、尺码都选对了;尺码选项和标题已滑出可视区;摘要为 `已选: #[新品闪购*夏日大卖]桔色 XL [建议110-120斤]` | **误拦** | | 2128(attempt 4183) | `dimension=color;stage=missing_proof;summaryPresent=0` | 颜色、尺码都选对了,且都可见;「颜色分类」标题已滑出可视区;摘要位置显示 `#快要抢光#[纯白]RW圆领 3XL码[145-165斤]` | **误拦** | | 2130(attempt 4181;11:47 的 attempt 4122 相同) | `dimension=color;stage=missing_proof;summaryPresent=0` | 摘要位置显示「请选择: 颜色分类 尺码」;提交按钮为「选择颜色分类及尺码后,提交订单」;没有任何选中项 | **拦得对**:规格丢失 | | 2131(attempt 4180) | 在选规格时失败,`PURCHASE_SPEC_SELECTION_UNCONFIRMED` | 摘要位置显示「请选择: 尺码」;提交按钮为「选择尺码后,提交订单」 | 不在本单范围 | - 2130(黑色 + L)6 次走到下单前复核,6 次都失败。同一商品 982178566127 的 2129(桔色 + XL)改完地址后规格仍然选中。这只能说明规格丢失**不是每次改地址都会发生**。规格丢在哪一步**尚无证据确认,不能归因于地址修改**,「黑色 + L」是否售罄也未核实(2026-09-28 采集任务 1520 时有货)。手机 logcat 已被覆盖。 - 历史上「创建订单前数量复核失败」(`PURCHASE_QUANTITY_MISMATCH`)共 13 次,全部是数量 ≥ 2 的任务。数量 ≥ 2 的任务走到下单前或已完成的约 110 次,数量 = 1 的约 1570 次,后者从未出现。推断是改地址后 PDD 把数量重置了,但未证实。 ### 补充真机文字证据(Codex 只读,2026-10-09) 用户保留未选中颜色、尺码的现场后,Codex 在指定测试手机上只读获取当前无障碍结构(PDD 包名 `com.xunmeng.pinduoduo`)。未点击、未滑动、未触发任务,原始树仅在内存解析,未落盘;以下仅记录不含个人信息的提示和结构: | 位置 | 实际文字 | 节点证据 | |---|---|---| | 面板上方摘要 | `请选择: 颜色分类 尺码` | 单个完整 `TextView`;`clickable=false`、`enabled=true`;无子节点 | | 面板底部提示 | `选择颜色分类及尺码后,提交订单` | 单个完整 `TextView`;`clickable=false`、`enabled=true`;无子节点,直接父节点也不可点击 | - 本次现场不存在提示拆成多个文字节点的情况;底部提示可被 v3 的完整文字规则匹配。 - 文字节点的 `enabled=true` 不能证明规格已选全或可以创建订单;文字节点不可点击也不能据此排除它所属的提交按钮区域。实际点击目标与所属可点击区域仍按既有结构定位。 - 此证据仅确认这一屏的文字与结构,不证明 #376 已实现、采购流程通过或其他布局全部覆盖。“拆分文字节点”仍作为合成结构回归用例,不当作本次失败根因。 ### 失败现场结构核对(Claude Code 只读,2026-10-09,快照 11 / attempt 4181) 本机解析后已删除,只记录结构: - 面板容器内最下方的可点击节点是底部横条 `FrameLayout`(bounds `[0,2159][1080,2306]`)。按 `finalSubmitTargets` 的规则,它就是被选中的提交行 `row`。 - 「选择颜色分类及尺码后,提交订单」是一个 `TextView`,层级为 `TextView` → 不可点击的 `LinearLayout` → 上述 `FrameLayout`。它的最近可点击祖先就是 `row`,而且它是 `row` 内唯一带文字的节点。 - 结论:在这个真实布局下,只读取 `row` 内文字的规则能读到完整提示,和 Codex 的真机观察(文字节点的直接父节点不可点击)一致。 ### 代码事实(`origin/main` `3ee8dfc0aa93ef9020786244cce29c487631ddbe`) - 执行顺序是 `SELECT_SPEC` → `SET_QUANTITY` → `VERIFY_UNIT_PRICE` → `VERIFY_ORDER_SUMMARY` → `UPDATE_SHIPPING_ADDRESS` → `CREATE_ORDER`(`PurchaseRehearsalExecutor.kt:140-165`),某一步失败后,后面的步骤都不执行。 - `CREATE_ORDER` 依次执行 `finalConfirmation` → `beforeOrderSubmit(evidence)` → `irreversibleStarted = true` → `submitOrderOnce`(`:161-178`)。 - `beforeOrderSubmit`(`AgentForegroundService.kt:865-878`)先在本地写 `markOrderSubmitStarted`(含 `final_confirmation_json`),再调用服务端 `markPurchaseOrderSubmitStarted`。 - 此后任何异常都会被转成 `order_result_unknown`,现有 `submitOrderOnce` 在点击前失败的 `PURCHASE_SUBMIT_TARGET_AMBIGUOUS` 也是这样。 - `final_confirmation_json` **只存在手机本地**(`PurchaseTaskStore.kt:130-139`),不上传服务端;代码中没有任何地方解析它。其中 `quantity` 字段取自下发的目标数量(`FinalConfirmationEvidence.quantity = input.quantity`)。 - **选规格**(`selectExactSpecWithRetry`、`isExactSpecSelected`,`:594-693`):目标已经选中就不点;否则点击目标,点击后必须读到目标处于选中状态,或者摘要匹配,否则失败。 - **改地址前的复核有漏洞**:`verifySummary`(`:1123`)→ `verifyExactSpecSelection`(`:751`)。 - 没有「已选」摘要时(`selectedSummary == null`,例如面板显示的是「请选择: …」),只要选规格时记录过证明,就直接判为通过(`attempt_selection_state`),即使目标选项就在屏幕上且没有选中。 - 摘要匹配、但选项不可见时,同样沿用历史证明(`attempt_selection_proof`)。 - **下单前复核**:`finalConfirmation`(`PurchaseLiveAutomation.kt:314`)依次检查地址、唯一提交按钮、规格(`PurchaseFinalSpecVerifier.verify`,#374,要求每个维度都有可见证据或摘要整段相等,否则 `missing_proof`)、价格、数量。 - `finalSubmitTargets`(`PurchaseLiveAutomation.kt:882`)主要按结构定位:在已识别面板范围内选择底部可点击行,再返回该行内符合条件的带文字节点供 `clickFresh` 重定位并向上找到可点击祖先;既有支付类文字排除保持不变。`FINAL_SUBMIT_MARKERS` / `legacyMarker` 只是诊断信号,不是定位放行条件。因此「选择颜色分类及尺码后,提交订单」仍可能被结构定位为提交目标,须另加未选提示检查;不能描述为靠「提交订单」文字定位。 ## 目标 1. 规格是否选对,在**改地址之前**严格核对,不再沿用历史记录来掩盖当前的未选状态。 2. 改地址之后**不再核对颜色、尺码、数量**,只确认提交按钮不是「选择…后,提交订单」;价格、地址、提交按钮唯一的检查照旧。 3. 规格丢失时**不点击**假提交按钮。在最终复核阶段发现时按普通失败处理,重购继续。 4. 点提交前记录屏幕状态,便于事后分析。 ## 非目标 - 不重新选规格,不在进入商品页时清除已选规格。 - 改地址后不比较颜色、尺码的值,不核对数量。 - 不在规格列表中滑动取证,不剥离摘要营销标签。 - 不移动提交边界(`beforeOrderSubmit`)的位置,不改本地存储和服务端边界协议,不上传 `final_confirmation_json`。 - 不处理 2131 的点击后未选中、2127 的从微信恢复超时,不查 2130 的组合是否售罄。 - 不改服务端、API、数据库和 Web。不实现任何支付动作。 ## 方案 ### 0. 共用判断(新函数,只在规格复核中使用) - **按钮未选提示**:只检查 `finalSubmitTargets` 唯一目标所属的实际提交按钮区域,区域必须可见且位于当前面板内;沿用既有底部行与最近可点击祖先关系,不改变点击目标选择。读取该区域当前可见的提示文字,而不是只依赖返回的单个文字节点或 `enabled` 属性。完整单节点提示直接检查;若同一按钮的提示拆分到多个文字节点,按明确的阅读顺序组合属于同一按钮的文字片段,不重复叠加父子节点相同文字,不拼入其他按钮、嵌套独立可点击子按钮、规格列表、面板摘要或不可见旧节点。不扩大到全屏搜索。去掉全部空白后,必须从头到尾完整匹配:`^(选择|選擇).+(后|後)[,,](提交订单|提交訂單)$`。不使用「包含某个词」的判断。此文字来源规则在改地址前、`finalConfirmation` 与 `submitOrderOnce` 的提示检测中共用;不新增规格值或数量复核。 - **具体拼接规则**: 1. 以 `finalSubmitTargets` 已选出的行 `row` 为范围,不只看返回的 `chosen`; 2. 只取 `row` 子树中可见、自身有文字、子孙都没有文字的节点; 3. 这些节点的最近可点击祖先必须是 `row`,与现有 `leafCandidates` 的条件相同,从而排除嵌套的独立可点击子按钮; 4. 按 `bounds.top`、再按 `bounds.left` 排序后直接拼接。 - 不复用现有的 `rowSubtreeLabels`:它把 `row.label` 和全部子孙 label 拼在一起,在 label 会上传给父节点的布局下会重复。 - 建议 `finalSubmitTargets` 一并返回 `row`、`chosen` 和拼接后的文字,三处调用共用;点击目标仍是 `chosen`,行的选择、唯一性和支付排除逻辑不变。实施时选最小改法。 - **摘要未选提示**:在当前可见的规格面板内(沿用 #374 的面板范围),处在摘要位置、可见、不可点击的文字。去掉全部空白后以「请选择」或「請選擇」开头,后面可以跟全角或半角冒号。不在全屏搜索。 - **目标可见但未选中**:某个维度中,与目标完全相等(`normalizeFinalConfirmation`)的选项可见、可选,且未选中(`selected`、`checked` 都为 false,沿用解析器的父子聚合);同维度没有其他选中项;面板内也没有「已选」摘要。 ### 1. 改地址前的复核(`verifySummary`,加严,第 5 题) - 判断每个目标维度之前,以及每次重新定位滑动之后,都先检查**摘要未选提示**和**按钮未选提示**(按钮提示只在当前面板识别出唯一提交按钮时检查)。出现任一提示就失败,原因 `selection_prompt`。 - `attempt_selection_state` 和 `attempt_selection_proof` 这两条沿用历史证明的路径,只在当前屏幕出现**目标可见但未选中**时改为失败,原因 `target_visible_unselected`。目标选项不可见时仍然沿用历史证明,**这两条路径不是全部取消**。 - 其余路径不变:看到目标选中、摘要匹配且候选唯一。`verifySummary` 中现有的数量和价格检查也不变。 - 错误码仍为 `PURCHASE_SPEC_SELECTION_UNCONFIRMED`,诊断里的 `reason` 使用新值。失败发生在改地址之前,不执行改地址。 ### 2. 改地址后的下单前复核(`finalConfirmation`,放宽,第 1、2、6 题) - **保留**:地址复核、提交按钮唯一、价格在区间内,判断内容不变。 - **新增**:唯一提交按钮出现**按钮未选提示**时,报 `PURCHASE_SPEC_NOT_MATCHED`,详情 `finalSpec;stage=selection_prompt`,不含页面文字。这一步在 `beforeOrderSubmit` **之前**,所以是普通失败:不写本地和服务端的提交边界,不点击,任务记为 `failed`,重购继续下一个任务。 - **移除**:`PurchaseFinalSpecVerifier` 的全部规格判断(`missing_proof`、摘要整段相等、`selected_conflict`、`candidate_collision`、`unavailable`、`summary_conflict`、`composition_ambiguity`),以及数量核对(`PURCHASE_QUANTITY_MISMATCH`)。改地址后不检查摘要未选提示,只记录(见方案 4)。 - 只用当前这一张截图,不滑动、不点击。 ### 3. 点击前兜底(`submitOrderOnce`) - 点击前截图时,如果唯一提交按钮出现**按钮未选提示**,就不点击并抛出异常。 - 此时提交边界已经写入,按现有逻辑结果**如实保留为 `order_result_unknown`**,边界只写这一次。要把这个零点击分支变成确定的失败,必须扩大到本地存储和服务端边界协议,不在本单范围;需要时另行建单并确认。 - 这个分支只在「最终复核通过、下一次截图才出现提示」时触发,主防线是方案 2。 ### 4. 只记录、不拦截的屏幕状态(第 4 题) - `FinalConfirmationEvidence` 新增: - `observedQuantity`:唯一可见可用数量输入框中的数字;如果不是恰好一个,记为空; - `selectedSummaryPresent`:面板内是否有「已选」摘要; - `summaryPromptPresent`:面板内是否有摘要未选提示。 - 写入本地 `final_confirmation_json` 时,原 `quantity` 键改为 `targetQuantity`,并增加上面三项。新增字段只有数字和布尔值,不含页面文字和个人信息。 - 只记录,不参与任何判断;不上传服务端。事后分析需读取手机本地数据库,上传另行建单。 ### 用本批现场对照 | 任务 | 改地址前(方案 1) | 改地址后(方案 2、3) | |---|---|---| | 2128 | 不变 | 放行(按钮是正常的「提交订单」) | | 2129 | 不变 | 放行 | | 2130 | 规格如果在这之前就丢了:以 `selection_prompt` 或 `target_visible_unselected` 失败,不执行改地址 | 规格如果到这里才丢:以 `selection_prompt` 普通失败,不点击、不写边界 | ## 子项目影响、依赖与并行 - Android: - `PurchaseRehearsalExecutor.kt`(`verifySummary` / `verifyExactSpecSelection`); - `PurchaseLiveAutomation.kt`(`finalConfirmation`、`submitOrderOnce`、`FinalConfirmationEvidence`); - `PurchaseFinalSpecVerifier.kt`(改为只做按钮提示判断,或者删除后由新函数替代,实施时选最小改法); - `AgentForegroundService.kt`(`beforeOrderSubmit` 中 JSON 键名和新增字段); - 必要时 `PddProductDetailCollector.kt`(只读取面板内的摘要提示,不改现有解析行为); - 以及对应测试。 - Server/Web:无。数据库、API:无。 - 依赖 #374(已合入)。不与其他修改采购执行器的工单并行。 ## 设计证据 非 UI 改动,无需原型;以本正文为准。 ## 验收标准 改地址前(方案 1): - [ ] 2130 的脱敏结构(「请选择: 颜色分类 尺码」+「选择颜色分类及尺码后,提交订单」,没有选中项)→ 失败,`reason=selection_prompt`,没有执行改地址。 - [ ] 只有摘要提示 → 失败;只有按钮提示 → 失败。 - [ ] 没有提示、没有「已选」摘要、目标尺码 L 可见但未选中、有历史证明 → 失败,`target_visible_unselected`(原来会以 `attempt_selection_state` 通过)。 - [ ] 目标选项不可见、没有摘要、没有提示、有历史证明 → 仍然通过(行为不变)。 - [ ] 不暴露选中属性的布局:有「已选」摘要时不受影响;没有摘要、也没有选中属性时会失败,按风险第 2 条记录为已知行为。 改地址后(方案 2): - [ ] 2128、2129 的脱敏结构(正常「提交订单」按钮)→ 放行。 - [ ] 2130 的脱敏结构 → `PURCHASE_SPEC_NOT_MATCHED`(`stage=selection_prompt`)。**执行器层面**验证:`beforeOrderSubmit` 没有被调用,本地没有 `order_submit_started`,没有点击,任务记为 `failed`。 - [ ] 可见选中项不等于目标、没有按钮提示 → 放行(按用户决定,作为已知行为保留用例)。 - [ ] 数量输入框不等于目标数量 → 放行(按用户决定,作为已知行为保留用例)。 - [ ] 地址复核失败、提交按钮不唯一、价格超出区间 → 照旧失败,相关测试不删除。 - [ ] 下单前复核不调用任何点击或滑动。 点击前兜底(方案 3): - [ ] 最终复核通过,`submitOrderOnce` 截图时按钮出现提示 → 不点击;执行器结果为 `order_result_unknown`,提交边界只写一次。 提示识别正反例(方案 0): - [ ] 按上述真机脱敏结构:摘要与底部提示分别是完整单个 `TextView`,均 `enabled=true`,底部文字节点及直接父节点不可点击 → 仍通过既有结构关联其实际按钮区域并识别未选提示;不能因文字节点启用或不可点击而漏判。最终复核在边界前普通失败、不点击;点击前兜底保留既定 unknown 语义。 - [ ] 合成拆分布局:同一个提交按钮区域内,`选择颜色分类及尺码后,` 和 `提交订单` 分处两个可见文字节点,返回的点击文字节点只含后一段 → 组合该按钮文字后能识别;父子重复标签不重复拼接。此项是其他布局的回归,不是本次现场事实。 - [ ] 合成隔离反例:提示片段分属不同按钮、独立可点击子按钮或按钮区域外 → 不跨区域拼成未选提示;原有按钮定位、唯一性及支付排除检查不变。 - [ ] 提示在面板外(例如商品详情页规格入口「请选择 颜色分类」)→ 不算提示。 - [ ] 不可见的旧节点 → 不算提示。 - [ ] 普通「提交订单」、「现在买,仅…」、「确认购买」按钮 → 不算提示。 - [ ] 简体、繁体、全角逗号、半角逗号、带空格的形式 → 能识别;文字只是包含「提交订单」但不符合完整格式 → 不算提示。 - [ ] 改地址前,当前面板类型不在 `PURCHASE_CONFIRMATION_PANEL_TYPES` 中(`finalSubmitTargets` 返回空)→ 只检查摘要提示,不因找不到按钮而报错。 - [ ] `finalConfirmation` 中 `finalSubmitTargets` 返回空或不唯一 → 仍按现有逻辑报 `PURCHASE_SUBMIT_TARGET_AMBIGUOUS`,不受新规则影响。 屏幕状态记录(方案 4): - [ ] `final_confirmation_json` 中有 `targetQuantity`、`observedQuantity`、`selectedSummaryPresent`、`summaryPromptPresent`,原 `quantity` 键已经不存在;数量输入框不是恰好一个时,`observedQuantity` 为空;不含页面文字和个人信息。 回归: - [ ] `PurchaseFinalSpecConfirmationTest` 按新规则改写,在回写中逐条说明删除或改写的用例;`verifySummary`、地址、价格、提交按钮相关测试通过;Android 构建通过,如实记录。 - [ ] 真机验证需要用户另行授权(正式采购可能真实下单);未执行时如实记录。 ## 风险与回退 1. **剩余风险:规格(用户已确认)**。改地址后,如果 PDD 把规格换成了其他值,同时提交按钮仍然是正常的「提交订单」,就会下错规格。目前还没有观察到这种情况;改地址前的复核会严格核对。 2. **剩余风险:数量(用户已确认,第 2 题 B)**。改地址后数量如果被重置,会按错误数量下单。历史上数量 ≥ 2 的任务约每 8~9 次就有 1 次被原来的数量核对拦下,原因未证实。建议采购员付款前核对数量;`observedQuantity` 可以用来事后核查。 3. 不暴露选中属性、也没有「已选」摘要的面板布局上,改地址前的 `target_visible_unselected` 可能误拦。这是偏安全的方向。 4. 改地址前的复核加严后,部分任务会提前失败。这些任务原本也会在后面失败,只是失败得更早。 5. 方案 3 的兜底分支仍会产生 `order_result_unknown`,需要人工核对,重购会停。只有在最终复核到点击之间页面发生变化时才会走到这里。 6. 回退:恢复 #374 的下单前复核、数量核对和原来的 `verifySummary`;无数据迁移。`final_confirmation_json` 的键名变化只影响新写入的记录。 ## 文档影响 - 更新 Wiki Business-Rules-and-Glossary(采购执行): - 改地址前严格核对规格; - 改地址后只确认提交按钮不是「选择…后,提交订单」,并检查价格、地址、提交按钮唯一; - 不核对规格值和数量,以及由此带来的剩余风险; - 本地最终证据中的字段。 - 先改线上 Wiki 并回读 revision,再执行一次 sync 和一次 sync --check。 ## 备注 本单由 Claude Code 依据线上只读查询、失败现场快照(本机解析后已删除)、代码阅读、与用户的问答和 Codex 审核意见起草;不含账号、地址、Cookie 或 Token。
ila changed title from fix(android): 下单前规格复核识别摘要营销标签,并滑动规格列表取得选中证据(#374 后续) to fix(android): 规格复核前移到改地址前,改地址后只拦 PDD 未选规格提示(#374 后续) 2026-10-09 16:27:07 +08:00
Author
Owner

2026-10-09 Claude Code 审核回复(SynapBus #129/#130,Codex 对 v2 的意见)

基线 origin/main 3ee8dfc0aa93ef9020786244cce29c487631ddbe。以下为讨论意见,正文尚未修改;把这些修订并入正文需用户确认。

结论

Codex 的三点和补充都已核实成立,建议全部并入正文。第 1 点是 v2 的错误,必须修改。

1. 提交边界(必须修改)

已核实:PurchaseRehearsalExecutor.kt:161-178 的顺序是 finalConfirmation → beforeOrderSubmit(evidence) → irreversibleStarted = true → submitOrderOnce。beforeOrderSubmit(AgentForegroundService.kt:865-878)会先写本地 markOrderSubmitStarted,再调用服务端 markPurchaseOrderSubmitStarted。submitOrderOnce 内抛出的任何异常,都会被外层转成 order_result_unknown。现有的 PURCHASE_SUBMIT_TARGET_AMBIGUOUS(点击前就失败)也是这样处理的。v2 方案 3 写「submitOrderOnce 内检查,不会进入订单结果不明」,这一说法不成立。

建议修订:

  • 主防线放在 finalConfirmation:它在提交边界之前。出现未选提示(包括「选择…后,提交订单」按钮)时,按普通失败处理(PURCHASE_SPEC_NOT_MATCHED),不调用 beforeOrderSubmit,不写本地和服务端边界。
  • submitOrderOnce 只做兜底:点击前截图时如果出现同样的提示,就不点击。但这时边界已经写入,结果如实保留现有的保守状态 order_result_unknown。不移动持久化边界,不改协议。
  • 如果要让「最终复核通过、下一次截图才出现提示」这个零点击分支变成确定的失败,需要扩大到本地存储和服务端边界协议,不在本单范围,需要时另行建单并确认。
  • 测试要在执行器层面验证:
    • finalConfirmation 遇到提示 → 任务失败,beforeOrderSubmit 没有被调用,本地没有写入 order_submit_started;
    • 最终复核通过、submitOrderOnce 截图时出现提示 → 没有点击,结果是 order_result_unknown,边界只写一次。

2. 未选提示的范围(必须修改)

  • 摘要提示:只在当前可见的规格面板内查找(沿用 #374 的面板范围)。节点必须是摘要位置上可见、不可点击的文字。去掉全部空白后,以「请选择」或「請選擇」开头(后面可以跟全角或半角冒号)。不在全屏搜索「请选择」,也不用「包含某个词」的方式判断。
  • 按钮提示:只看 finalSubmitTargets 认出的那一个提交按钮,并且它必须可见、位于面板内。去掉空白后,文字必须完整匹配「(选择|選擇) + 任意内容 + (后|後) + (,|,) + (提交订单|提交訂單)」,从开头匹配到结尾。
  • 正反例测试:提示在面板外(例如商品详情页的规格入口「请选择 颜色分类」);不可见的旧节点;只有按钮提示;只有摘要提示;普通「提交订单」按钮;「现在买,仅…」按钮;简体和繁体;全角和半角逗号;带空格的形式。
  • target_visible_unselected:只在 attempt_selection_state 和 attempt_selection_proof 这两条路径上,且当前屏幕的目标选项可见并且 selected/checked 为 false 时才生效。选项不可见时仍然沿用历史证明,历史证明路径没有全部取消。另外保留「布局不暴露选中属性」的回归测试:有「已选」摘要时不受影响;既没有摘要、也没有选中属性时,按正文风险第 2 条记录为可能误拦。

3. 根因表述(必须修改)

已核实:同一商品的另一个规格改地址后保持选中,只能说明规格清空不是每次改地址都会发生,不能排除「地址修改导致部分组合被清空」。建议把正文里的「不成立」改为:「尚无证据确认,不能归因于地址修改。规格丢在哪一步、『黑色 + L』是否售罄,都未核实。」

补充(采纳)

PurchaseFinalSpecConfirmationTest 按新规则改写时,明确保留一条「目标不符但没有提示,也放行」的已知行为用例。地址、价格、数量、提交按钮唯一性的测试不删除。验收里会写明这一点。

未验证项

本次只读了代码,没有运行测试,没有装机,也没有真机验证。

## 2026-10-09 Claude Code 审核回复(SynapBus #129/#130,Codex 对 v2 的意见) 基线 `origin/main` `3ee8dfc0aa93ef9020786244cce29c487631ddbe`。以下为讨论意见,正文尚未修改;把这些修订并入正文需用户确认。 ### 结论 Codex 的三点和补充都已核实成立,建议全部并入正文。第 1 点是 v2 的错误,必须修改。 ### 1. 提交边界(必须修改) 已核实:`PurchaseRehearsalExecutor.kt:161-178` 的顺序是 `finalConfirmation` → `beforeOrderSubmit(evidence)` → `irreversibleStarted = true` → `submitOrderOnce`。`beforeOrderSubmit`(`AgentForegroundService.kt:865-878`)会先写本地 `markOrderSubmitStarted`,再调用服务端 `markPurchaseOrderSubmitStarted`。`submitOrderOnce` 内抛出的任何异常,都会被外层转成 `order_result_unknown`。现有的 `PURCHASE_SUBMIT_TARGET_AMBIGUOUS`(点击前就失败)也是这样处理的。v2 方案 3 写「`submitOrderOnce` 内检查,不会进入订单结果不明」,这一说法不成立。 建议修订: - **主防线放在 `finalConfirmation`**:它在提交边界之前。出现未选提示(包括「选择…后,提交订单」按钮)时,按普通失败处理(`PURCHASE_SPEC_NOT_MATCHED`),不调用 `beforeOrderSubmit`,不写本地和服务端边界。 - **`submitOrderOnce` 只做兜底**:点击前截图时如果出现同样的提示,就不点击。但这时边界已经写入,结果**如实保留现有的保守状态 `order_result_unknown`**。不移动持久化边界,不改协议。 - 如果要让「最终复核通过、下一次截图才出现提示」这个零点击分支变成确定的失败,需要扩大到本地存储和服务端边界协议,**不在本单范围**,需要时另行建单并确认。 - 测试要在执行器层面验证: - `finalConfirmation` 遇到提示 → 任务失败,`beforeOrderSubmit` 没有被调用,本地没有写入 `order_submit_started`; - 最终复核通过、`submitOrderOnce` 截图时出现提示 → 没有点击,结果是 `order_result_unknown`,边界只写一次。 ### 2. 未选提示的范围(必须修改) - **摘要提示**:只在当前可见的规格面板内查找(沿用 #374 的面板范围)。节点必须是摘要位置上可见、不可点击的文字。去掉全部空白后,以「请选择」或「請選擇」开头(后面可以跟全角或半角冒号)。不在全屏搜索「请选择」,也不用「包含某个词」的方式判断。 - **按钮提示**:只看 `finalSubmitTargets` 认出的那一个提交按钮,并且它必须可见、位于面板内。去掉空白后,文字必须完整匹配「(选择|選擇) + 任意内容 + (后|後) + (,|,) + (提交订单|提交訂單)」,从开头匹配到结尾。 - **正反例测试**:提示在面板外(例如商品详情页的规格入口「请选择 颜色分类」);不可见的旧节点;只有按钮提示;只有摘要提示;普通「提交订单」按钮;「现在买,仅…」按钮;简体和繁体;全角和半角逗号;带空格的形式。 - **`target_visible_unselected`**:只在 `attempt_selection_state` 和 `attempt_selection_proof` 这两条路径上,且当前屏幕的目标选项可见并且 `selected/checked` 为 false 时才生效。选项不可见时仍然沿用历史证明,**历史证明路径没有全部取消**。另外保留「布局不暴露选中属性」的回归测试:有「已选」摘要时不受影响;既没有摘要、也没有选中属性时,按正文风险第 2 条记录为可能误拦。 ### 3. 根因表述(必须修改) 已核实:同一商品的另一个规格改地址后保持选中,只能说明规格清空不是每次改地址都会发生,不能排除「地址修改导致部分组合被清空」。建议把正文里的「不成立」改为:「尚无证据确认,不能归因于地址修改。规格丢在哪一步、『黑色 + L』是否售罄,都未核实。」 ### 补充(采纳) `PurchaseFinalSpecConfirmationTest` 按新规则改写时,明确保留一条「目标不符但没有提示,也放行」的已知行为用例。地址、价格、数量、提交按钮唯一性的测试不删除。验收里会写明这一点。 ### 未验证项 本次只读了代码,没有运行测试,没有装机,也没有真机验证。
ila changed title from fix(android): 规格复核前移到改地址前,改地址后只拦 PDD 未选规格提示(#374 后续) to fix(android): 规格复核前移到改地址前;改地址后不核对规格和数量,只拦「选择…后,提交订单」(#374 后续) 2026-10-09 16:45:46 +08:00
Author
Owner

2026-10-09 Claude Code 复核回复(SynapBus #133/#134,Codex 对 v3 的补充)

基线 origin/main 3ee8dfc0aa93ef9020786244cce29c487631ddbe;正文按 2026-10-09 16:51:12 的版本读取。

结论

Codex 的三点补充成立,方向可以实施,下面给出最小修正。但正文当前已损坏(见下文「正文损坏」),实施前必须先修复。

代码更正已核实

finalSubmitTargets(PurchaseLiveAutomation.kt:882-948)的做法:

  1. 在面板容器内取最下方的可点击行;
  2. 如果整行文字含支付类词语,就排除;
  3. 在这一行内,取「最近可点击祖先就是这一行」、可见、启用、有文字的节点,从中选最靠右下的一个返回。

FINAL_SUBMIT_MARKERS 只用来算诊断字段 legacyMarker,不参与定位。v3 中「按『提交订单』等标记识别」的说法有误,Codex 的更正正确。

三点补充:可以实施,最小修正如下

  1. 文字来源:用 finalSubmitTargets 已经选出的那一行 row,不能只用返回的 chosen 节点。建议把行和按钮文字一起返回,例如 SubmitTarget(row, chosen, text),三处调用(改地址前、finalConfirmation、submitOrderOnce)共用这个结果。点击目标仍然是 chosen,选择逻辑不变。

  2. 拆分文字的组合规则,写成可测试的形式:

    • 只取 row 子树内自身有文字、子孙节点都没有文字的可见节点;
    • 这些节点的最近可点击祖先必须是 row,这一条和 leafCandidates 的过滤条件相同;
    • 按 bounds.top、再按 bounds.left 排序后拼接;
    • 不使用父节点「汇总后的」label。现有 rowSubtreeLabels 是把 row.label 和全部子孙的 label 拼起来,在 label 会传给父节点的布局下会重复,所以不能复用。

    v3 的完整正则作用于拼接后的文字;单个完整节点(本次真机现场就是这样)属于同一规则的特例。

  3. 隔离:第 2 点中「最近可点击祖先必须是 row」已经排除了嵌套的独立可点击子按钮。行外节点、摘要、规格列表不在 row 子树里,不可见节点被可见性条件排除。现有的支付排除、行并列判断和唯一性检查不变。

补充:改地址前那一步,如果当前面板类型不在 PURCHASE_CONFIRMATION_PANEL_TYPES 中,finalSubmitTargets 会返回空,这时只检查摘要提示,不做按钮检查。这与 v3「识别出唯一提交按钮时才检查」一致,建议在验收里加一条用例。

正文损坏(必须修复)

方案 0「按钮未选提示」那一行的正则结尾 $` 丢了,原位置被插入了一份从「## 基本信息」到「### 0. 共用判断(新函数,只在规格复核中使用)」的正文副本,然后才接上「。不使用「包含某个词」的判断……」。因此当前正文中「基本信息」到「方案 0」这一段出现了两次,正则也不完整。

推测原因:更新时用了字符串替换,替换内容中的 $` 被当作「匹配位置之前的全部文本」展开了(JavaScript String.replace 等的特殊替换模式)。这是推测,未证实。

修复方法:删除插入的副本,恢复正则结尾 $`。修改正文需要用户确认。

未验证项

本次只读了代码和正文,没有运行测试,没有装机,也没有真机验证。

## 2026-10-09 Claude Code 复核回复(SynapBus #133/#134,Codex 对 v3 的补充) 基线 `origin/main` `3ee8dfc0aa93ef9020786244cce29c487631ddbe`;正文按 2026-10-09 16:51:12 的版本读取。 ### 结论 Codex 的三点补充成立,方向可以实施,下面给出最小修正。但**正文当前已损坏**(见下文「正文损坏」),实施前必须先修复。 ### 代码更正已核实 `finalSubmitTargets`(`PurchaseLiveAutomation.kt:882-948`)的做法: 1. 在面板容器内取最下方的可点击行; 2. 如果整行文字含支付类词语,就排除; 3. 在这一行内,取「最近可点击祖先就是这一行」、可见、启用、有文字的节点,从中选最靠右下的一个返回。 `FINAL_SUBMIT_MARKERS` 只用来算诊断字段 `legacyMarker`,不参与定位。v3 中「按『提交订单』等标记识别」的说法有误,Codex 的更正正确。 ### 三点补充:可以实施,最小修正如下 1. **文字来源**:用 `finalSubmitTargets` 已经选出的那一行 `row`,不能只用返回的 `chosen` 节点。建议把行和按钮文字一起返回,例如 `SubmitTarget(row, chosen, text)`,三处调用(改地址前、`finalConfirmation`、`submitOrderOnce`)共用这个结果。点击目标仍然是 `chosen`,选择逻辑不变。 2. **拆分文字的组合规则**,写成可测试的形式: - 只取 `row` 子树内**自身有文字、子孙节点都没有文字**的可见节点; - 这些节点的最近可点击祖先必须是 `row`,这一条和 `leafCandidates` 的过滤条件相同; - 按 `bounds.top`、再按 `bounds.left` 排序后拼接; - 不使用父节点「汇总后的」label。现有 `rowSubtreeLabels` 是把 `row.label` 和全部子孙的 label 拼起来,在 label 会传给父节点的布局下会重复,所以**不能复用**。 v3 的完整正则作用于拼接后的文字;单个完整节点(本次真机现场就是这样)属于同一规则的特例。 3. **隔离**:第 2 点中「最近可点击祖先必须是 `row`」已经排除了嵌套的独立可点击子按钮。行外节点、摘要、规格列表不在 `row` 子树里,不可见节点被可见性条件排除。现有的支付排除、行并列判断和唯一性检查不变。 补充:改地址前那一步,如果当前面板类型不在 `PURCHASE_CONFIRMATION_PANEL_TYPES` 中,`finalSubmitTargets` 会返回空,这时只检查摘要提示,不做按钮检查。这与 v3「识别出唯一提交按钮时才检查」一致,建议在验收里加一条用例。 ### 正文损坏(必须修复) 方案 0「按钮未选提示」那一行的正则结尾 `` $` `` 丢了,原位置被插入了一份从「## 基本信息」到「### 0. 共用判断(新函数,只在规格复核中使用)」的正文副本,然后才接上「。不使用「包含某个词」的判断……」。因此当前正文中「基本信息」到「方案 0」这一段出现了两次,正则也不完整。 推测原因:更新时用了字符串替换,替换内容中的 `` $` `` 被当作「匹配位置之前的全部文本」展开了(JavaScript `String.replace` 等的特殊替换模式)。这是推测,未证实。 修复方法:删除插入的副本,恢复正则结尾 `` $` ``。修改正文需要用户确认。 ### 未验证项 本次只读了代码和正文,没有运行测试,没有装机,也没有真机验证。
Author
Owner

2026-10-09 用户明确授权实施 #376。按正文 v3(17:01:22,含评论 9101 的最小细化)开始:基线 main 3ee8dfc0aa93ef9020786244cce29c487631ddbe;分支 fix/376-pre-address-spec-verification,独立 worktree D:/OPC/goauto-worktrees/issue-376。严格限 Android、相关测试及既定 Wiki 业务规则更新;先测试、再实现、独立复核后提交推送。保留已确认的规格/数量放宽风险,不改提交边界协议、不改 Server/Web/业务库。本次不装机、不执行真实采购/付款、不合并 main 或发布。

2026-10-09 用户明确授权实施 #376。按正文 v3(17:01:22,含评论 9101 的最小细化)开始:基线 main `3ee8dfc0aa93ef9020786244cce29c487631ddbe`;分支 `fix/376-pre-address-spec-verification`,独立 worktree `D:/OPC/goauto-worktrees/issue-376`。严格限 Android、相关测试及既定 Wiki 业务规则更新;先测试、再实现、独立复核后提交推送。保留已确认的规格/数量放宽风险,不改提交边界协议、不改 Server/Web/业务库。本次不装机、不执行真实采购/付款、不合并 main 或发布。
Author
Owner

2026-10-09 实施与装机完成,待验收

范围与提交

  • 实现:9c7357609cee7c73b57edd030136ed12ef9485b6。
  • Wiki 镜像:a953a5e9fbe01cbef6d08c97d024167eab248c75。
  • 工单分支 fix/376-pre-address-spec-verification 已推送,远端回读与本地 HEAD 一致。首次 Git 推送认证失败,重试成功,未更改凭据。
  • 严格限 Android 与业务规则 Wiki;没有 Server/Web、数据库迁移、API 或权限变更。未合并 main、未发布或重启线上服务。
  • 删除已被本契约取代且无调用的 PurchaseFinalSpecVerifier.kt,新增有界摘要观察 PurchaseSelectionEvidence.kt。不改普通采集器实现或规格点击选择,不新增分享、OCR、重新选规格和支付。
  • 改地址前先拦当前未选提示,并拒绝可见未选目标借历史证明放行;离屏历史证明保留。改地址后按用户决定不复核规格值/数量;地址、价格和原提交目标检查保留。按钮提示从既有 row 中末级可见标签组合,chosen 点击目标不变。
  • 边界前提示为 failed、不调用提交边界;边界后提示零点击但保留 order_result_unknown。没有移动持久化边界。
  • 本地 JSON 新写入使用 targetQuantity,附 observedQuantity(显式 null)、selectedSummaryPresent、summaryPromptPresent;不上传,原记录不迁移。

验证证据

  • 首轮 TDD RED:8 项中 7 项按新契约失败;随后隐藏子标签反例 RED 1/1 失败,再修复。
  • 主代理使用 --rerun-tasks 强制重跑:19 套件 418 项通过,0失败、0错误、0跳过,24 个 Gradle task 实际执行。
  • 过滤器:*Purchase*Test、*SpecPanelRecognitionTest、*SpecValueNormalizerTest、*TruncatedSpecCardTest、*PddProductDetailCollectorTest、*SpecOptionDedupTest、*PddNavigationTest、*SpecClickDiagnosticTest。
  • assembleDebug、compileReleaseUnitTestKotlin、git diff --check 通过。编译仍有未修改文件的既有 deprecated/unused 警告。
  • 独立规格复核及代码质量复核均通过,未发现需修正问题。
  • 执行器测试覆盖第一/第二维、重定位后提示停止;边界前 callback=0/click=0,边界后 callback=1/click=0/result unknown;正常按钮下错误规格/数量允许继续是显式已知行为。
  • 验证限制:上述边界测试使用模拟回调;JSON 有序列化单测与 service→store 静态核对,没有真实 SQLite/服务端边界端到端测试。未执行真实采购、地址修改、下单或付款。未跑完整 Android 全量测试(既有 ImageSearchBackRecovery 忙循环不在本单)。
  • harness.py check --strict 在未修改基线即失败:docs/evidence/pdd-home-35727-summary.md 未登记为 Wiki 镜像,源于既有 a16e692;本次不混入治理修复。核心 Wiki 一致性检查另外通过。

文档

  • 线上先更新并回读 Business-Rules-and-Glossary,revision f8bb75d1fc0b5e8822186c740ac2034fbd562057;明确旧 #374 与新 #376 行为及风险边界。
  • 执行一次 harness.py sync、一次 sync --check,17 个核心镜像一致,只有业务规则镜像变化。

用户追加授权的覆盖安装

  • 目标手机 192.168.0.9:39459,安装前 ONLINE、无 current_task_id 标记。
  • adb install -r 返回 Success;未卸载、未清数据、未修改服务器配置。
  • 安装前后 settings、device identity、UI preferences 三个文件哈希一致,原配置和设备身份保留。
  • 安装后设备 base.apk SHA256 与构建包一致:ce48656d2d2173b258a0ab467fe02fbffbe3d1552d78f4d897cdcba433670575。
  • 原签名 SHA256:bf86d7465c6092be74ce9c4187eb30c9a7d045c3b91891a547e2598429766dec。
  • 版本标签仍为 0.9.69-373-fix1 / code82,本次未调整版本号;必须用上述哈希区分已包含 #376 的新包,不能只看版本名。
  • APK:D:/OPC/goauto-worktrees/issue-376/android/app/build/outputs/apk/debug/app-debug.apk。
  • 没有触发采集/采购或正式订单验证;等待用户业务验收。分支尚未合并,按规则保留 worktree,不清理。

原 PurchaseFinalSpecConfirmationTest 用例逐项处理

原用例 本次处理
bracket display variants and offscreen color are proven by full panel summary 删除最终摘要等值证明要求;改由正常按钮+离屏规格放行用例覆盖
summary above scroll area is accepted for scrollable and non scrollable sheets 删除最终依赖摘要位置补证的门禁;保留摘要范围观察测试
checked only exact option and physical parent child duplicates provide selection proof 删除最终选中证明要求;原解析器聚合与采集回归保留
selected other color or size overrides matching summary and positive target 改为正常按钮允许错误可见规格的已知行为
selected bracket variants are not a conflict 最终不再比较值;规范化函数独立测试保留
distinct physical identical or normalized target options are collisions 改为正常按钮不因最终候选碰撞拦截
explicit unavailable target cannot be rescued by summary 改为最终正常按钮不因目标不可用状态拦截
all required selected proofs take priority over a single non proving summary 删除最终证明优先级与组合冲突门禁
selected options retain established parser separation of trailing display price 删除最终规格尾价证明门禁;普通采集/规格解析相关测试保留
unselected visible options alone and unrelated title cannot prove selection 删除最终缺选中证据门禁;改地址前未选历史证明单独拒绝测试
panel external prefixed summary is ignored even at same coordinates 改为摘要观察标志的面板外隔离测试
structural ancestry overrides textual path prefix 原最终规格证明用例删除;新摘要/按钮范围反例覆盖结构归属,不再把摘要当最终放行证据
whole summary rejects substring sizes colors extra dimensions quantity and unsupported separators 删除整段摘要相等/格式最终门禁;正常按钮不读规格值
known candidates making another full composition reject ambiguous summary 删除最终组合歧义门禁
summary permits invisible color despite another unselected visible color 改为正常按钮允许离屏/缺标题,无需摘要证明
required single dimension must equal whole summary and empty pair is never proof 删除最终摘要维度等值要求;不改早期目标与选规格校验
anchored selected prefix variants preserve internal colons commas and whitespace 删除最终摘要等值规则;新布尔摘要观察仅认已选前缀
conflicting scoped summaries reject even both exact options selected 删除最终摘要冲突拒绝
display normalization is narrow and content preserving 该套件冗余用例删除,SpecValueNormalizerTest 的同规则独立测试保留并通过
existing structurally recognized unprefixed summary is usable 删除无前缀摘要最终补证;明确无已选前缀不计 selectedSummaryPresent
same dimension groups retain earlier selected conflicts and physical candidates 删除最终维度组冲突门禁;默认采集去重兼容测试保留
collector default still collapses same raw labels and leaves summary behavior unchanged 改名 collector opt in retains independent candidates without changing regular parsing,保留默认/opt-in候选及摘要兼容断言
independently bounded selected options survive absent full panel boundary 删除最终选中证明要求;只观察有可信范围的摘要
price quantity and address checks remain enforced 保留地址/价格拒绝并新增缺按钮;最终数量不符改为允许并记录 target/observed

其他夹具调整:一条 SpecPanelRecognitionTest 的定位页面改为正常提交文案;两条 TruncatedSpecCardTest 的已完成选规格假页面不再显示“请选择”。原定位、去重、点击次数和 target-first 断言保留。

## 2026-10-09 实施与装机完成,待验收 ### 范围与提交 - 实现:`9c7357609cee7c73b57edd030136ed12ef9485b6`。 - Wiki 镜像:`a953a5e9fbe01cbef6d08c97d024167eab248c75`。 - 工单分支 `fix/376-pre-address-spec-verification` 已推送,远端回读与本地 HEAD 一致。首次 Git 推送认证失败,重试成功,未更改凭据。 - 严格限 Android 与业务规则 Wiki;没有 Server/Web、数据库迁移、API 或权限变更。未合并 main、未发布或重启线上服务。 - 删除已被本契约取代且无调用的 `PurchaseFinalSpecVerifier.kt`,新增有界摘要观察 `PurchaseSelectionEvidence.kt`。不改普通采集器实现或规格点击选择,不新增分享、OCR、重新选规格和支付。 - 改地址前先拦当前未选提示,并拒绝可见未选目标借历史证明放行;离屏历史证明保留。改地址后按用户决定不复核规格值/数量;地址、价格和原提交目标检查保留。按钮提示从既有 row 中末级可见标签组合,chosen 点击目标不变。 - 边界前提示为 failed、不调用提交边界;边界后提示零点击但保留 order_result_unknown。没有移动持久化边界。 - 本地 JSON 新写入使用 targetQuantity,附 observedQuantity(显式 null)、selectedSummaryPresent、summaryPromptPresent;不上传,原记录不迁移。 ### 验证证据 - 首轮 TDD RED:8 项中 7 项按新契约失败;随后隐藏子标签反例 RED 1/1 失败,再修复。 - 主代理使用 `--rerun-tasks` 强制重跑:19 套件 **418 项通过,0失败、0错误、0跳过**,24 个 Gradle task 实际执行。 - 过滤器:`*Purchase*Test`、`*SpecPanelRecognitionTest`、`*SpecValueNormalizerTest`、`*TruncatedSpecCardTest`、`*PddProductDetailCollectorTest`、`*SpecOptionDedupTest`、`*PddNavigationTest`、`*SpecClickDiagnosticTest`。 - `assembleDebug`、`compileReleaseUnitTestKotlin`、`git diff --check` 通过。编译仍有未修改文件的既有 deprecated/unused 警告。 - 独立规格复核及代码质量复核均通过,未发现需修正问题。 - 执行器测试覆盖第一/第二维、重定位后提示停止;边界前 callback=0/click=0,边界后 callback=1/click=0/result unknown;正常按钮下错误规格/数量允许继续是显式已知行为。 - **验证限制**:上述边界测试使用模拟回调;JSON 有序列化单测与 service→store 静态核对,没有真实 SQLite/服务端边界端到端测试。未执行真实采购、地址修改、下单或付款。未跑完整 Android 全量测试(既有 ImageSearchBackRecovery 忙循环不在本单)。 - `harness.py check --strict` 在未修改基线即失败:`docs/evidence/pdd-home-35727-summary.md` 未登记为 Wiki 镜像,源于既有 `a16e692`;本次不混入治理修复。核心 Wiki 一致性检查另外通过。 ### 文档 - 线上先更新并回读 Business-Rules-and-Glossary,revision `f8bb75d1fc0b5e8822186c740ac2034fbd562057`;明确旧 #374 与新 #376 行为及风险边界。 - 执行一次 `harness.py sync`、一次 `sync --check`,17 个核心镜像一致,只有业务规则镜像变化。 ### 用户追加授权的覆盖安装 - 目标手机 `192.168.0.9:39459`,安装前 ONLINE、无 current_task_id 标记。 - `adb install -r` 返回 Success;未卸载、未清数据、未修改服务器配置。 - 安装前后 settings、device identity、UI preferences 三个文件哈希一致,原配置和设备身份保留。 - 安装后设备 base.apk SHA256 与构建包一致:`ce48656d2d2173b258a0ab467fe02fbffbe3d1552d78f4d897cdcba433670575`。 - 原签名 SHA256:`bf86d7465c6092be74ce9c4187eb30c9a7d045c3b91891a547e2598429766dec`。 - 版本标签仍为 `0.9.69-373-fix1 / code82`,本次未调整版本号;必须用上述哈希区分已包含 #376 的新包,不能只看版本名。 - APK:`D:/OPC/goauto-worktrees/issue-376/android/app/build/outputs/apk/debug/app-debug.apk`。 - 没有触发采集/采购或正式订单验证;等待用户业务验收。分支尚未合并,按规则保留 worktree,不清理。 ### 原 PurchaseFinalSpecConfirmationTest 用例逐项处理 | 原用例 | 本次处理 | |---|---| | `bracket display variants and offscreen color are proven by full panel summary` | 删除最终摘要等值证明要求;改由正常按钮+离屏规格放行用例覆盖 | | `summary above scroll area is accepted for scrollable and non scrollable sheets` | 删除最终依赖摘要位置补证的门禁;保留摘要范围观察测试 | | `checked only exact option and physical parent child duplicates provide selection proof` | 删除最终选中证明要求;原解析器聚合与采集回归保留 | | `selected other color or size overrides matching summary and positive target` | 改为正常按钮允许错误可见规格的已知行为 | | `selected bracket variants are not a conflict` | 最终不再比较值;规范化函数独立测试保留 | | `distinct physical identical or normalized target options are collisions` | 改为正常按钮不因最终候选碰撞拦截 | | `explicit unavailable target cannot be rescued by summary` | 改为最终正常按钮不因目标不可用状态拦截 | | `all required selected proofs take priority over a single non proving summary` | 删除最终证明优先级与组合冲突门禁 | | `selected options retain established parser separation of trailing display price` | 删除最终规格尾价证明门禁;普通采集/规格解析相关测试保留 | | `unselected visible options alone and unrelated title cannot prove selection` | 删除最终缺选中证据门禁;改地址前未选历史证明单独拒绝测试 | | `panel external prefixed summary is ignored even at same coordinates` | 改为摘要观察标志的面板外隔离测试 | | `structural ancestry overrides textual path prefix` | 原最终规格证明用例删除;新摘要/按钮范围反例覆盖结构归属,不再把摘要当最终放行证据 | | `whole summary rejects substring sizes colors extra dimensions quantity and unsupported separators` | 删除整段摘要相等/格式最终门禁;正常按钮不读规格值 | | `known candidates making another full composition reject ambiguous summary` | 删除最终组合歧义门禁 | | `summary permits invisible color despite another unselected visible color` | 改为正常按钮允许离屏/缺标题,无需摘要证明 | | `required single dimension must equal whole summary and empty pair is never proof` | 删除最终摘要维度等值要求;不改早期目标与选规格校验 | | `anchored selected prefix variants preserve internal colons commas and whitespace` | 删除最终摘要等值规则;新布尔摘要观察仅认已选前缀 | | `conflicting scoped summaries reject even both exact options selected` | 删除最终摘要冲突拒绝 | | `display normalization is narrow and content preserving` | 该套件冗余用例删除,SpecValueNormalizerTest 的同规则独立测试保留并通过 | | `existing structurally recognized unprefixed summary is usable` | 删除无前缀摘要最终补证;明确无已选前缀不计 selectedSummaryPresent | | `same dimension groups retain earlier selected conflicts and physical candidates` | 删除最终维度组冲突门禁;默认采集去重兼容测试保留 | | `collector default still collapses same raw labels and leaves summary behavior unchanged` | 改名 collector opt in retains independent candidates without changing regular parsing,保留默认/opt-in候选及摘要兼容断言 | | `independently bounded selected options survive absent full panel boundary` | 删除最终选中证明要求;只观察有可信范围的摘要 | | `price quantity and address checks remain enforced` | 保留地址/价格拒绝并新增缺按钮;最终数量不符改为允许并记录 target/observed | 其他夹具调整:一条 SpecPanelRecognitionTest 的定位页面改为正常提交文案;两条 TruncatedSpecCardTest 的已完成选规格假页面不再显示“请选择”。原定位、去重、点击次数和 target-first 断言保留。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#376