docs: import wiki at afc651f75a3a
+205
@@ -0,0 +1,205 @@
|
||||
<!-- docs-wiki-sync:docs/tasks/T-265.md@afc651f75a3abc2676bb13aa8a80f6aa6a25a72e -->
|
||||
> 同步来源:[`docs/tasks/T-265.md`](/chengma/mroubao/src/commit/afc651f75a3abc2676bb13aa8a80f6aa6a25a72e/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)`。
|
||||
|
||||
## 验收要点
|
||||
|
||||
- [x] 安全入口存在时优先使用,不点击购买入口,有单测证明。
|
||||
- [x] 安全入口缺失时使用「免拼购买」入口,能打开规格面板。
|
||||
- [x] 两者皆无时返回 `ENTRY_ABSENT`,行为与 T-264 一致。
|
||||
- [x] 落到订单确认页时调用既有返回动作、跳过该候选、不重试,有单测证明。
|
||||
- [x] 订单确认页路径不调用任何提交订单/支付/扣款语义动作,有单测证明。
|
||||
- [x] 退出订单确认页失败时仍返回 `Blocked(PAYMENT_BOUNDARY)`。
|
||||
- [x] `specEntryViaPurchase` 与 `specLandedOnCheckout` 计数正确并出现在诊断 message。
|
||||
- [x] T-263/T-264 的支付边界与订单确认页判据未被削弱,有回归测试。
|
||||
- [x] 登录、验证码、风控判定与优先级未变。
|
||||
- [x] 既有诊断键顺序、名称、取值不变。
|
||||
- [x] 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 两个
|
||||
诊断计数仍待验证。
|
||||
Reference in New Issue
Block a user