用户 2026-09-18:「这次工单主要解决没有按照指定天数遍历点击"pdd app-我的订单"订单里所有订单详情入口」。
背景:真机 CTN5T20416012406 触发回填,默认 2 天窗口,结果「已检查 6 · 成功 0 · 已回填 0 · 冲突/失败 0,滚动后无法确认订单详情,未完整扫描」——远未遍历完 2 天内应有的订单数。
scan() 读单张卡片详情时用 check() 直接抛异常:
scan()
check()
check(BackfillPagePolicy.detail(detail)) { "点击后未识别订单详情" } ... check(BackfillPagePolicy.detail(detail)) { "滚动后无法确认订单详情,未完整扫描" }
这两处都没有任何 try/catch 包住单张卡片,异常一路冒泡到 scan() 最外层,被 AgentForegroundService 顶层 catch 后整个回填任务直接结束。只要遍历过程中任何一单的详情读取失败一次,无论第几单,2 天窗口内其余所有订单都不会再检查——这就是「已检查 6」后中止、没有遍历完指定天数的直接原因,与具体哪一单为什么失败无关,这个结构性缺陷本身就会导致提前收尾。
AgentForegroundService
真机现场停在订单列表(非详情页),但检查时间已滞后且不确定期间是否有人工操作,不作为触发原因的确证;本工单只解决「失败即中止整轮」这个结构性问题,不深究具体触发条件。
把详情读取逻辑抽成 readDetail(): BackfillDetail?,两处判据从 check()(抛异常)改为返回 null(信号「这一单读不到」)。scan() 收到 null 时:
readDetail(): BackfillDetail?
null
readFailures
awaitOrders()
seenCards
checkActive()(用户取消、10 分钟上限、服务器/设备身份变化)不受影响,仍直接抛出并立即中止——只有「这一单读不到」被降级为跳过,真正的中止条件不变。
checkActive()
跳过的单数写入最终结果文案(finish() 追加"有 N 单详情读取失败已跳过,未纳入结果"),不悄悄吞掉。
finish()
跳过路径复用已有的 awaitOrders() 恢复机制,不新增独立恢复逻辑;checkActive() 触发的中止条件未改变。回退即把两处 if (!detail) return null 换回 check()。
if (!detail) return null
无长期文档影响:未改入口、配置、接口,只改回填扫描器内部的失败处理策略。
提交 bd78fc2(deploy-main)。抽出 readDetail(),两处判据从 check() 改为返回 null;scan() 遇到 null 时计数、调用 awaitOrders() 恢复后继续下一张卡片;finish() 追加跳过单数说明。
bd78fc2
readDetail()
真机验证——你手上暂时没有真正有采购记录(含 _cg 标记订单)的手机可测。这条改动能不能让 CTN5T20416012406 遍历完 2 天窗口,需要等能确认「失败后确实恢复到列表并继续」这一步在真机上成立;awaitOrders() 的恢复逻辑本身(#317/#318)也还没有被完整扫描流程验证过。
状态:待验收。
No dependencies set.
The note is not visible to the blocked user.
原始需求
用户 2026-09-18:「这次工单主要解决没有按照指定天数遍历点击"pdd app-我的订单"订单里所有订单详情入口」。
背景:真机 CTN5T20416012406 触发回填,默认 2 天窗口,结果「已检查 6 · 成功 0 · 已回填 0 · 冲突/失败 0,滚动后无法确认订单详情,未完整扫描」——远未遍历完 2 天内应有的订单数。
事实(代码复核,2026-09-18)
scan()读单张卡片详情时用check()直接抛异常:这两处都没有任何 try/catch 包住单张卡片,异常一路冒泡到
scan()最外层,被AgentForegroundService顶层 catch 后整个回填任务直接结束。只要遍历过程中任何一单的详情读取失败一次,无论第几单,2 天窗口内其余所有订单都不会再检查——这就是「已检查 6」后中止、没有遍历完指定天数的直接原因,与具体哪一单为什么失败无关,这个结构性缺陷本身就会导致提前收尾。真机现场停在订单列表(非详情页),但检查时间已滞后且不确定期间是否有人工操作,不作为触发原因的确证;本工单只解决「失败即中止整轮」这个结构性问题,不深究具体触发条件。
方案
把详情读取逻辑抽成
readDetail(): BackfillDetail?,两处判据从check()(抛异常)改为返回null(信号「这一单读不到」)。scan()收到 null 时:readFailures,不提交任何数据;awaitOrders()尝试恢复到列表——它已有「停在陈旧详情页先退出」(#318)和「长时间空壳重新加载」(#317)的恢复路径;seenCards,不会被重新挑中);awaitOrders()自己超时)才真正中止,这种情况值得停下来。checkActive()(用户取消、10 分钟上限、服务器/设备身份变化)不受影响,仍直接抛出并立即中止——只有「这一单读不到」被降级为跳过,真正的中止条件不变。跳过的单数写入最终结果文案(
finish()追加"有 N 单详情读取失败已跳过,未纳入结果"),不悄悄吞掉。验收
check()写法后该用例必须红。风险与回退
跳过路径复用已有的
awaitOrders()恢复机制,不新增独立恢复逻辑;checkActive()触发的中止条件未改变。回退即把两处if (!detail) return null换回check()。文档影响
无长期文档影响:未改入口、配置、接口,只改回填扫描器内部的失败处理策略。
实施
提交
bd78fc2(deploy-main)。抽出readDetail(),两处判据从check()改为返回 null;scan()遇到 null 时计数、调用awaitOrders()恢复后继续下一张卡片;finish()追加跳过单数说明。验证
check()写法后该用例变红。未验证
真机验证——你手上暂时没有真正有采购记录(含 _cg 标记订单)的手机可测。这条改动能不能让 CTN5T20416012406 遍历完 2 天窗口,需要等能确认「失败后确实恢复到列表并继续」这一步在真机上成立;
awaitOrders()的恢复逻辑本身(#317/#318)也还没有被完整扫描流程验证过。状态:待验收。