1
T-265
ila edited this page 2026-08-07 16:37:07 +08:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

同步来源:docs/tasks/T-265.md · commit afc651f75a3a


id: T-265 title: 恢复购买入口作为唯一规格入口并依赖订单确认页识别安全回退 phase: 2 deps:

  • T-264 status: DOING created: 2026-07-31 context_ref: d856c0b work_branch: null write_paths:
  • docs/tasks/T-265.md
  • docs/current-state.md
  • android-buyer/app/src/main/**
  • android-buyer/app/src/test/**

问题 / 背景

T-264 移除「免拼购买」兜底点击后,真机三轮每一个候选都无法打开规格面板:

轮次 attempts specOpenFailed specEntryAbsent reason
1 2 2 2 CANDIDATE_SPECIFICATION_UNAVAILABLE
2 4 4 4 CANDIDATE_SPECIFICATION_UNAVAILABLE
3 3 3 3 CANDIDATE_SPECIFICATION_UNAVAILABLE

specEntryAbsent 恒等于 attempts,即覆盖损失 100%。

真机取证:详情页根本没有独立的规格入口

对一个真实服装商品详情页 dump(190 节点),全部可见文本中没有任何 「选择规格」「请选择规格」「颜色分类」「颜色款式」「选择颜色」「选择尺码」,也没有 以「请选择:」或「已选:」开头的文本。整页只有标题、价格、优惠券、拼单信息、店铺、 分享/收藏/客服,以及底部的:

'已优惠6元 免拼购买'

当前拼多多版本的商品详情页不提供独立的规格入口——「免拼购买」就是唯一入口,点击 后才弹出规格面板供选择颜色和尺码。

T-264 的判断错误

T-264 依据纸巾案例(点「免拼购买」直接进入订单确认页)推断该兜底本身危险,予以移除。 但真实情况是:

商品 点「免拼购买」后
正常服装(有颜色/尺码) 弹出规格面板,流程正常
纸巾(无可选规格)+ 促销 直接进入订单确认页

问题不在于点击该入口,而在于点击后落到订单确认页时无法识别、无法退出。 后者已由 T-264 的原生订单确认页识别修复。

openPinduoduoSpecifications() 的既有安全入口匹配(SAFE_ENTRY_TEXTS / SAFE_ENTRY_PREFIXES)仍然保留,只是当前版本页面不命中;未来版本若恢复独立入口, 该路径将优先生效。

关联需求与交互

  • 功能:F-005、F-007
  • 用户故事:US-004、US-006
  • 交互:不新增采购操作
  • 架构/API:沿用既有诊断机制,后端零改动

行为契约

一、恢复购买入口,但仅作为次优先路径

openPinduoduoSpecifications() 恢复「免拼购买」入口点击,顺序不变:

  1. 优先匹配 SAFE_ENTRY_TEXTS / SAFE_ENTRY_PREFIXES 的安全入口;
  2. 仅当第 1 步找不到唯一目标时,才使用「免拼购买」入口;
  3. 两者都找不到时返回 ENTRY_ABSENT,维持 T-264 的跳过行为。

除「免拼购买」外,不得新增任何其他购买、下单、拼单、支付语义控件作为入口。

二、落到订单确认页即判定该候选无可选规格

点击入口后 awaitSpecificationEntry() 返回 ORDER_CONFIRMATION 时:

  1. 调用既有 returnFromOrderConfirmation() 退出(沿用其现有实现与有界次数);
  2. 将该候选判定为「无可选规格」,跳过并继续下一个候选,不得对同一候选重试点击;
  3. 退出失败时维持既有 Blocked(SafetyStopReason.PAYMENT_BOUNDARY) 行为。

依据:任务的 SKU 硬约束要求颜色与尺码,而点击规格入口却直接进入下单流程,说明该商品 不存在可选规格,不可能满足硬约束。

三、订单确认页上零点击

这是硬边界。 在订单确认页上,除既有 returnFromOrderConfirmation() 的返回动作外, 不得点击任何控件,尤其不得点击提交订单、立即支付、免密支付、先用后付或任何扣款 语义控件。必须有单测证明该路径不调用任何此类动作。

四、诊断可见

追加计数,置于既有键之后:

specEntryViaPurchase=<n> specLandedOnCheckout=<n>
键 含义
specEntryViaPurchase 通过「免拼购买」入口打开规格的次数
specLandedOnCheckout 点击入口后落到订单确认页并被跳过的候选数

specLandedOnCheckout 是本次恢复的安全审计口径:它直接度量自动化到达订单确认页的 频率。若真机上该值偏高,说明大量候选无可选规格,应在更早阶段过滤(如品类判断), 而非依赖事后回退。

五、既有安全能力一律不放松

  • 不改 T-264 的原生订单确认页识别与 hasOrderConfirmation 任一判据。
  • 不改 T-263 结构判据、hasCheckoutRoot、paymentMarkers 及其抑制名单。
  • 不改登录、验证码、风控的检测逻辑与优先级。
  • 不改 returnFromOrderConfirmation() 的既有实现与有界次数。
  • 不改 T-261 清理逻辑与 isSafeForCleanup。
  • 不改 T-256/T-258/T-259/T-260 的成果。
  • 既有诊断键顺序、名称、取值逐字节不变,新键追加在末尾。

方案

  1. openPinduoduoSpecifications() 恢复「免拼购买」为第二优先入口,返回值区分 经由哪条入口打开,ENTRY_ABSENT 语义不变。
  2. PinduoduoCandidateAutomation 在 ORDER_CONFIRMATION 分支将候选计为 specLandedOnCheckout 并跳过,不重试。
  3. 两个新计数并入诊断快照与 message 尾部。
  4. 单测覆盖:安全入口存在时优先使用且不点购买入口;安全入口缺失时使用购买入口; 两者皆无时返回 ENTRY_ABSENT;落到订单确认页时只调用返回动作并跳过候选; 订单确认页路径不调用任何提交/支付语义动作;退出失败仍返回 Blocked(PAYMENT_BOUNDARY)。

验收要点

  • 安全入口存在时优先使用,不点击购买入口,有单测证明。
  • 安全入口缺失时使用「免拼购买」入口,能打开规格面板。
  • 两者皆无时返回 ENTRY_ABSENT,行为与 T-264 一致。
  • 落到订单确认页时调用既有返回动作、跳过该候选、不重试,有单测证明。
  • 订单确认页路径不调用任何提交订单/支付/扣款语义动作,有单测证明。
  • 退出订单确认页失败时仍返回 Blocked(PAYMENT_BOUNDARY)。
  • specEntryViaPurchase 与 specLandedOnCheckout 计数正确并出现在诊断 message。
  • T-263/T-264 的支付边界与订单确认页判据未被削弱,有回归测试。
  • 登录、验证码、风控判定与优先级未变。
  • 既有诊断键顺序、名称、取值不变。
  • Android Debug/Release 单测、lintDebug、assembleDebug、assembleRelease 全部通过。
  • 真机验证:重跑采购任务能打开规格面板并进入 SKU 匹配;从 Admin 读取 specEntryViaPurchase 与 specLandedOnCheckout 记入执行记录。

边界

  • 除「免拼购买」外不新增任何购买语义控件作为入口。
  • 订单确认页上除既有返回动作外零点击,绝不提交订单或支付。
  • 不改 T-261/T-262/T-263/T-264 的任何安全判据与清理逻辑。
  • 不改候选卡片识别、签名算法、跨轮去重、价格解析或三轮预算。
  • 不改后端代码、数据库、API 契约或 Admin 模板。
  • 不在本任务实现品类过滤。若 specLandedOnCheckout 偏高,应另开任务在候选筛选 阶段引入品类判断(可考虑接入既有候选评估 VLM),而非在此处堆规则。

附带记录(供后续价格任务参考)

同一次商品详情页取证显示价格文本形态为:

'券后¥15.98'      前缀「券后」
'券后 ¥ 15.98'    含空格
'¥'  '15.98'      货币符号与数字被拆成两个独立节点

与 T-257 观测到的 pricePrefix 占比吻合,并新增一个此前未知的因素:价格被拆成多个 节点,这是 PRICE_PATTERN.matchEntire 失败的另一独立原因。价格解析任务需同时处理 前缀与节点拆分两种情况。

该页面同时显示 # 先用后付 # 支持0元下单,确认收货后再付款,说明先用后付在正常服装 商品上同样存在,不能以其存在与否作为跳过依据;下单路径排除信用支付需另行设计。

执行记录

  • 2026-07-31:恢复唯一「免拼购买」次优先入口。入口选择先按 SAFE_ENTRY_TEXTS/SAFE_ENTRY_PREFIXES 得到唯一安全目标;仅无唯一安全目标时 才接受唯一且文本以「免拼购买」结尾的目标,其它购买、下单、拼单和支付文本仍拒绝。
  • 2026-07-31:PinduoduoSpecificationOpenOutcome 区分安全入口与购买入口; 候选循环对购买入口和落到订单确认页分别累计 specEntryViaPurchase/ specLandedOnCheckout。订单确认页继续只调用既有 returnFromOrderConfirmation();成功返回后跳过当前候选,失败保持 Blocked(PAYMENT_BOUNDARY)。
  • 2026-07-31:两个诊断键追加在既有 payPage 之后;旧键顺序、名称和格式不变。 单测按动作发生页面证明 ORDER_CONFIRMATION 上唯一动作是返回,返回到商品详情后 才执行回搜索结果页;同一候选不重试,下一候选可继续进入规格匹配。
  • 2026-07-31:Debug/Release 各 336 项 App 单测零失败,lintDebug、 assembleDebug、assembleRelease 均通过;根 init.ps1 以及全部 Go 后端测试 通过。
  • 2026-07-31:adb devices -l 无已连接设备,因此不能执行最后一项真机采购任务 重跑和 Admin 诊断读取。任务保持 DOING,不伪造 specEntryViaPurchase/specLandedOnCheckout 真机结果。
  • 2026-07-31:设备重新连接后,通过 USB 在 OnePlus PKG110 Android 16/API 36 覆盖安装 T-265 Debug APK;项目未在本任务修改版本号,设备仍显示 1.4.18 (23),包更新时间为 2026-07-31 17:20:18。MainActivity 正常启动, 采购无障碍、悬浮窗、通知和 Shizuku 权限均保持启用。采购任务重跑和 Admin 两个 诊断计数仍待验证。