docs: import wiki at afc651f75a3a
+126
@@ -0,0 +1,126 @@
|
||||
<!-- docs-wiki-sync:docs/tasks/T-251.md@afc651f75a3abc2676bb13aa8a80f6aa6a25a72e -->
|
||||
> 同步来源:[`docs/tasks/T-251.md`](/chengma/mroubao/src/commit/afc651f75a3abc2676bb13aa8a80f6aa6a25a72e/docs/tasks/T-251.md) · commit `afc651f75a3a`
|
||||
|
||||
---
|
||||
id: T-251
|
||||
title: 修复候选结果页早判与三轮耗尽后执行不终止
|
||||
phase: 2
|
||||
deps:
|
||||
- T-248
|
||||
- T-250
|
||||
status: DONE
|
||||
created: 2026-07-30
|
||||
context_ref: 9e399e7
|
||||
work_branch: null
|
||||
write_paths:
|
||||
- docs/tasks/T-251.md
|
||||
- docs/current-state.md
|
||||
- android-buyer/app/src/main/**
|
||||
- android-buyer/app/src/test/**
|
||||
---
|
||||
|
||||
## 问题 / 背景
|
||||
|
||||
真机任务在 Admin 显示“执行中”,手机停在拼多多图片搜索结果页。现场状态表明三轮候选
|
||||
搜索均在候选浏览步骤返回 `TARGET_NOT_READY`,本地 attempt gate 已记录三次失败并禁止
|
||||
再次启动,但 execution 仍继续每 30 秒 heartbeat,服务端因此一直保持 `RUNNING`。
|
||||
|
||||
拼多多结果页的标题和排序栏会早于商品卡片稳定出现。现有代码在页面已被识别为结果页后
|
||||
立即读取候选卡;首次读取为空时会直接消耗滚动和本轮预算,不能区分“卡片仍在加载”、
|
||||
“规格不匹配”和“商品身份无法解析”。第三轮耗尽后只记录搜索事件,没有写入既有终态
|
||||
outbox,是服务端状态不能收敛的直接原因。
|
||||
|
||||
## 关联需求与交互
|
||||
|
||||
- 功能:F-004、F-005、F-006、F-007
|
||||
- 用户故事:US-003、US-004、US-006
|
||||
- 交互:沿用候选搜索进度、安全停止和任务详情页面,不新增采购操作
|
||||
- 架构/API:复用 T-207 的事件/终态 outbox 和 execution `FAIL` 上报,不修改后端契约
|
||||
|
||||
## 行为契约
|
||||
|
||||
### 候选卡就绪
|
||||
|
||||
- 结果页外壳识别成功后,候选浏览必须在当前步骤 timeout 内对候选卡做最长 10 秒的
|
||||
有界轮询;卡片出现后才允许开始检查商品或消耗结果滚动次数。
|
||||
- 轮询期间页面变为验证码、登录、风险控制、订单确认或支付页时,继续按既有安全策略
|
||||
立即停止,不把阻塞页面当作加载中。
|
||||
- 10 秒内没有任何可安全读取的候选卡时,本轮返回
|
||||
`CANDIDATE_RESULTS_NOT_READY`;不得以滚动成功伪装成已取得候选。
|
||||
- 就绪等待包含在 T-250 的候选浏览 100/45 秒 timeout 内,不增加三轮总预算。
|
||||
|
||||
### 失败分类
|
||||
|
||||
- 页面已出现候选卡,但规格弹层内颜色或尺码不满足任务硬约束时,使用
|
||||
`CANDIDATE_SKU_NOT_MATCHED`。
|
||||
- 候选可打开但无法取得稳定 `goods_id`、规范链接或身份指纹时,使用
|
||||
`CANDIDATE_IDENTITY_UNRESOLVED`。
|
||||
- 候选卡存在但在本轮检查/滚动上限内没有可保存候选,且不属于以上单一主因时,使用
|
||||
`CANDIDATE_TARGET_NOT_FOUND`。
|
||||
- 页面启动阶段原有 `TARGET_NOT_READY` 保留,不再作为候选采集的笼统结果。
|
||||
|
||||
### 三轮耗尽终态
|
||||
|
||||
- 每轮仍先通过既有 API 记录搜索尝试、轮次、原因和 `exhausted`。
|
||||
- 第三轮失败且 execution-scoped attempt gate 已耗尽时,App 必须追加一个
|
||||
`CANDIDATE_SEARCH_EXHAUSTED` 的 `FAIL` 终态 outbox;`step` 固定为
|
||||
`CANDIDATE_SEARCH`,`order_submitted=false`,并标为可安全重试。
|
||||
- 终态 outbox 必须复用当前 execution/generation 和幂等保护;后台同步上传成功后清理
|
||||
当前任务并停止 execution heartbeat,使 Admin 从 `RUNNING` 收敛到 `FAILED`。
|
||||
- 升级前已经耗尽三轮的本地状态必须被识别;若还没有终态 outbox,App 自动补写一次,
|
||||
若终态已经在 outbox 中则只补齐本地 `terminalQueued` 标记,不重复生成终态。
|
||||
- 三轮尚未耗尽时不得写终态;已增量回传的候选继续保留,现有重新执行和下单信号阻断
|
||||
规则不变。
|
||||
|
||||
## 方案
|
||||
|
||||
1. 在 `PinduoduoCandidateAutomation` 增加有界候选卡就绪轮询,并记录本轮是否见到卡片、
|
||||
规格不匹配和身份解析失败,用确定性优先级返回细分失败码。
|
||||
2. 为三轮搜索结果增加纯 Kotlin 终态策略,只在 gate 确认耗尽时生成固定的失败载荷;
|
||||
`MainActivity` 先记录轮次事件,再调用 `ProcurementRepository.failExecution`。
|
||||
3. 复用 `ProcurementExecutionService` 的 outbox flush 和 STOP 路径,不另建心跳开关,也
|
||||
不从拼多多页面执行任何下单、返回、支付或全局导航动作。
|
||||
4. 增加自动化单测覆盖延迟卡片、无卡片、SKU 不匹配、身份缺失,以及非终轮/终轮策略。
|
||||
|
||||
## 验收要点
|
||||
|
||||
- [x] 候选卡延迟出现时不消耗滚动或搜索轮次,并可继续采集。
|
||||
- [x] 结果页 10 秒无候选卡时返回 `CANDIDATE_RESULTS_NOT_READY`。
|
||||
- [x] SKU 不匹配和身份缺失分别返回稳定细分失败码。
|
||||
- [x] 第一、第二轮失败只记录事件;第三轮耗尽追加唯一 `FAIL` outbox。
|
||||
- [x] 升级前已经耗尽的 execution 可幂等补写终态。
|
||||
- [x] 终态上传后复用既有同步 STOP 路径清理任务并停止 heartbeat。
|
||||
- [x] T-248/T-250 的累计候选、第三轮保底、预算、随机停顿和支付边界不变。
|
||||
- [x] Android 单测、lint、Debug 和 Release 构建通过。
|
||||
|
||||
## 边界
|
||||
|
||||
- 不改变后端 execution 状态机、候选 API、Admin 选择授权或安全重试规则。
|
||||
- 不降低候选卡、商品身份、颜色、尺码、数量、价格和订单确认页校验。
|
||||
- 不把空白/加载页视作默认候选,不在本任务增加第四轮搜索。
|
||||
- 不启动真实拼多多采购,不进入订单提交或支付。
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-07-30:真机执行记录显示三轮均在 `pdd_browse_candidates` 失败并耗尽,
|
||||
`execution_report` 没有终态,服务仍持续 heartbeat;拼多多前台已显示完整图片搜索
|
||||
结果,确认同时存在结果卡片早判竞态和耗尽后未上报终态两个问题。
|
||||
- 2026-07-30:候选自动化增加生产默认 50 次、每次 200 毫秒的卡片就绪轮询;就绪前
|
||||
不滚动。候选终态按无卡片、SKU 不匹配、身份未解析和未找到目标四类稳定返回,启动
|
||||
阶段的 `TARGET_NOT_READY` 含义不变。
|
||||
- 2026-07-30:Main 统一通过 `recordAutomaticSearchFailure` 先记录轮次事件,再在第三轮
|
||||
耗尽时追加 `CANDIDATE_SEARCH_EXHAUSTED` 的可重试 `FAIL`。attempt gate 持久化
|
||||
`terminalQueued`,自动轮询还能恢复升级前已经三轮耗尽但没有终态的 execution;
|
||||
repository 既有 terminal outbox、同步后清理和 STOP 行为保持不变。
|
||||
- 2026-07-30:新增延迟卡片、空结果、SKU 不匹配、身份解析失败、三轮门禁恢复和终态
|
||||
策略测试。`testDebugUnitTest`、`lintDebug assembleDebug assembleRelease` 与根
|
||||
`init.ps1` 全部通过;根入口同时通过 Android Debug/Release 单测和 Go 后端全量测试。
|
||||
- 2026-07-30:本次未覆盖安装 APK、未启动 Roubao 或拼多多,也未触发真实采购;现场
|
||||
execution 从 `RUNNING` 收敛到 `FAILED` 需在安装新 APK 并启动 Roubao 后复验。
|
||||
- 2026-07-30:随后通过 USB 将最新 Debug APK 覆盖安装到 PKG110,`adb install -r`
|
||||
成功;手机 `base.apk` 与本地产物 SHA-256 均为
|
||||
`19ac6295e033f02693fa539128d2881a7c91d8924c73c7bb1a3f7e96cd2aadac`,版本仍为
|
||||
`1.4.16 (21)`。覆盖安装后 Roubao 采购无障碍仍在启用列表中。
|
||||
- 2026-07-30:为触发升级前耗尽状态恢复,仅启动 Roubao 主界面;没有启动拼多多或
|
||||
下单。随后 ADB 设备连接消失,且本机后端 `8080` TLS 握手超时,因此尚未确认
|
||||
`terminalQueued`、终态上传或 Admin 状态收敛。
|
||||
Reference in New Issue
Block a user