fix(android): 采购核单缺少订单金额时延迟一次只读补采 #392

Open
opened 2026-10-14 10:45:14 +08:00 by ila · 2 comments
Owner

This was generated by AI during triage.

状态、来源与关联

  • 类型:缺陷(bug);状态:方案已明确,待用户授权实施(ready-for-human / HITL);优先级:低。仓库当前没有标签,分类与状态记录于正文,不新增标签。
  • 来源:2026-10-14 用户要求分析线上采购成功但价格为空的问题;经解释后确认最小方向为“获取不到待支付价格时,再去获取一遍”,本轮明确要求“建工单”。
  • 本轮只授权建单,不包含代码实施、提交推送、合并、发布重启、装机或真机下单验证。
  • 讨论依据:SynapBus #goauto 消息 #184、#185 及 Claude 复核 #186;已吸收累积证据核对、页面上下文约束、单次独立补读及异常不降级的边界。
  • 关联:#325(待付款核单与应付金额)、#326(订单资料完整性与人工补全)、#365(支付页返回后的核单观察)。
  • 不记录真实订单号、生产任务标识、金额、地址、原始请求或控件树;回归使用合成样例。

已核验事实与证据边界

核验日期:2026-10-14。样例执行 Agent 0.9.71,相关代码基线 328afde;线上 Server 发布 5183df3。本轮及 Claude 复核的 main 9f918b0 仍保留同一核单结束逻辑。正式实施前须重新核对最新 main,不能把这些提交当作未来固定基线。

  1. 只读查询确认样例为 order_created,订单号、下单时间及下单前商品单价已保存,pdd_order_amount_cent 为空。
  2. 用已保存任务/attempt 字段重建“不含订单金额”的规范结果 JSON,其 SHA256 与服务端 result_hash 一致,确认当次上报未携带金额,而不是服务端收到后漏存。比对只在内存进行,不输出原始请求。
  3. PurchaseLiveAutomation.readOrderResult 累积符合订单/待付款上下文帧的可见标签,并在 parseOrderEvidence 返回非空时立即结束;订单号、时间及原有状态证据齐全,即使金额为 null 也会返回,不再等金额。
  4. parsePayableAmount 只识别单个 label 内符合“应付+金额+元”的内容;不会跨无关联节点拼接。不同金额冲突、缺失或溢出可导致 null。相同金额重复不构成冲突。
  5. PurchaseResultPayload 仅在金额非 null 时携带该字段;Server 对合法非 null 金额已有落库路径。同设备其他成功订单能正常带回金额。
  6. 样例成功结束,无对应失败现场快照。尚不能确定这一次属于加载慢、不可见、标签拆分、文字变化还是金额冲突。 本单针对已确认的“金额缺失无补读机会”做有界改善,不宣称重试必然解决该样例。
  7. 当前分析只读核验了数据链路与代码,未重现真实页面时序,也未执行本单新增测试。后续先写合成失败用例再实现。

目标与非目标

目标:第一次已确认订单创建、只缺订单金额时,停留当前页面,延迟约 1 秒进行最多一次额外只读采样;获取成功则补上金额,否则保持原结果。

非目标:

  • 不重新打开商品、不遍历“我的订单”、不重下单、不付款、不新增点击/返回/拉前台/滑动。
  • 不把下单前单价或单价×数量当作订单应付总额,不推断是否付款。
  • 不新增金额必填门禁;不因金额缺失把成功订单改成 failed 或 order_result_unknown。
  • 不扩大金额文案/币种/节点拼接支持,不改已有“应付”解析和有效性规则。
  • 不改 Server/Web、API、权限、业务库或 Android SQLite 结构,不改 SYB 回填逻辑,不补写历史数据。
  • 不调整既有支付页等待、单号/时间搜索、租约、任务串行及状态机,不引入通用重试框架或可配置项。

最小流程设计(非 UI)

设计依据:用户本轮确认的最小方向及 Claude #186,确认日期 2026-10-14。无界面变化,不要求 UI 原型;本正文作为待实施的流程和验收证据。

  1. 正常核单按原流程进行。首次取得合法 PurchaseOrderEvidence 时保存首次订单号、时间和已累积的 labels。
  2. 首次金额非 null(包括 0)时原样返回:不得新增 pause 或 capture。
  3. 首次金额为 null 时,只走独立补读步骤:约 1000ms pause,再 capture 一帧,最多一次。不重新进入原核单主循环,以免触发原循环的入口点击、返回或定期上滑路径。实际额外耗时还包括 capture,不承诺严格 1 秒墙钟上限。
  4. 补读帧必须来自 PDD 包且具备既有订单或待付款上下文;微信、系统应用选择页、无订单上下文的纯支付页、陌生/空窗口直接忽略。沿用既有“订单/待付款证据优先于复用支付 Activity 名称”的判定,不新增导航动作。
  5. 合格帧的可见 labels 并入同一订单读取过程的原累积集合,再解析一次。仅当并集能解析、订单号与首次相同、且金额为唯一合法值时采用新金额;最终订单号和下单时间始终使用首次已确认值。补读帧单独缺少重复显示的订单号时,仍依赖同一过程的累积证据,不另创猜测匹配。
  6. 并集出现其他订单号、多订单号、不同金额、溢出或其他解析失败时,保留首次订单号与时间,金额仍为空。不得只用第二帧覆盖第一帧,从而消除已经观察到的金额冲突。
  7. 补读无效或常规采样/解析异常时返回首次成功证据;不得调用会将任务抛成失败的 pageProblem,不得把已确认订单降级。保持既有线程取消/进程终止语义,不通过吞掉致命错误伪造完成。
  8. 复用原结果上报路径一次提交,不新增 result 请求或 attempt。

轻量诊断

若复用现有 panelDiagnostic 可实现,补读仍无金额时记录结构化分类与计数,例如 no_payable_label、conflict、invalid,及补读页面被忽略/读取异常;不得输出标签原文、价格、订单号、地址或控件树,不新增表/接口/上传管道。

分类必须与实际判定一致:缺少符合现有规则的金额,不得伪装成已证明的页面加载慢;未匹配文案也不能仅凭 null 就断言格式非法。诊断失败不得影响首次订单事实。仅采用必要的小范围诊断,不为分类重构整个金额解析器。

依赖、子项目与并行边界

  • 前置:最新 main 已有 #325/#326/#365 的订单结果和可选金额链路;本轮确认存在,实施时复核。
  • 交付单元:Android 核单返回处的小范围逻辑与相应单元测试;必要时私有辅助函数。数据模型与接口不变。
  • 与修改 PurchaseLiveAutomation.readOrderResult、订单证据或金额解析的工单不可并行编辑;无代码依赖的其他模块可并行,但本单不分派额外范围。
  • 正式实施按仓库规则创建单独 issue worktree;当前未创建开发分支或 worktree。

验收与测试

  • 首次已有唯一订单号、时间和合法金额:capture 次数、pause 总时长、返回字段及原流程均不变;0 元同样不补读。
  • 首次只缺金额,约 1 秒后的唯一补帧出现合法金额:补齐金额,订单号和时间保持首次值;恰好增加一次 pause 和一次 capture。
  • 第二帧仍无金额:保持 order_created 所需证据,金额为空,不循环。
  • 第二帧出现不同/多个订单号:忽略新金额,保留首次订单事实。
  • 第二帧是微信、系统选择页、纯支付页、陌生包或空窗口:忽略,不触发返回、点击、前台恢复或滑动,不降级为 unknown。
  • 首次累积金额冲突,补帧只剩其中一个金额:冲突仍存在,不猜值;同值父子重复则正常去重。
  • 金额解析无效/溢出、补读常规异常、诊断异常:保留首次订单号和时间及原成功结果,不造成二次下单。
  • 首次没有取得有效订单证据:不触发该补读机制,原等待/失败路径不变。
  • 用 mock driver 断言补读路径不增加 click/back/swipe/bring-to-foreground,不创建额外 attempt/result 上报。
  • 先执行受影响单测观察预期失败,再最小实现、全套 Android 单测及 APK 构建;记录实际命令、结果、提交及未验证项。
  • 真机行为/缺金额改善比例若未验证,明确标注,不用合成测试声称线上成功率提升。覆盖安装和真实采购须另行授权。
  • 实施、必要文档、提交推送与证据集中回写后停在待用户验收,不自行关闭。

风险、回退与授权

采购流程行为变化属于高风险,用户当前只要求建单。实施和真机操作按各自范围取得授权后进行。此改动只缓解金额迟到,不保证解决未识别文案或跨节点页面结构;不能据此承诺历史样例必然恢复。

保留首个成功结果是主要回归边界。回退为撤销本单独立补读逻辑;不涉及数据迁移、历史清理或订单撤销。部署/重启/真机执行不属于本单建单授权。

长期文档影响

实施确认后更新 Wiki Business-Rules-and-Glossary 的下单后核单金额读取流程:一次有界补读、首次事实保留、金额可空及无新增动作。若现有 API 契约仅描述字段和可选性,无需制造接口变化;实施时确认文档一致性。按 Wiki-first 在线修改、回读 revision,执行一轮 sync 与 sync --check 并提交镜像。

本次只建单,不提前修改 Wiki 宣称功能已实现,不创建任务归档或本地第二事实来源。

> *This was generated by AI during triage.* ## 状态、来源与关联 - 类型:缺陷(bug);状态:方案已明确,待用户授权实施(ready-for-human / HITL);优先级:低。仓库当前没有标签,分类与状态记录于正文,不新增标签。 - 来源:2026-10-14 用户要求分析线上采购成功但价格为空的问题;经解释后确认最小方向为“获取不到待支付价格时,再去获取一遍”,本轮明确要求“建工单”。 - 本轮只授权建单,不包含代码实施、提交推送、合并、发布重启、装机或真机下单验证。 - 讨论依据:SynapBus #goauto 消息 #184、#185 及 Claude 复核 #186;已吸收累积证据核对、页面上下文约束、单次独立补读及异常不降级的边界。 - 关联:#325(待付款核单与应付金额)、#326(订单资料完整性与人工补全)、#365(支付页返回后的核单观察)。 - 不记录真实订单号、生产任务标识、金额、地址、原始请求或控件树;回归使用合成样例。 ## 已核验事实与证据边界 核验日期:2026-10-14。样例执行 Agent 0.9.71,相关代码基线 `328afde`;线上 Server 发布 `5183df3`。本轮及 Claude 复核的 main `9f918b0` 仍保留同一核单结束逻辑。正式实施前须重新核对最新 main,不能把这些提交当作未来固定基线。 1. 只读查询确认样例为 `order_created`,订单号、下单时间及下单前商品单价已保存,`pdd_order_amount_cent` 为空。 2. 用已保存任务/attempt 字段重建“不含订单金额”的规范结果 JSON,其 SHA256 与服务端 `result_hash` 一致,确认当次上报未携带金额,而不是服务端收到后漏存。比对只在内存进行,不输出原始请求。 3. `PurchaseLiveAutomation.readOrderResult` 累积符合订单/待付款上下文帧的可见标签,并在 `parseOrderEvidence` 返回非空时立即结束;订单号、时间及原有状态证据齐全,即使金额为 null 也会返回,不再等金额。 4. `parsePayableAmount` 只识别单个 label 内符合“应付+金额+元”的内容;不会跨无关联节点拼接。不同金额冲突、缺失或溢出可导致 null。相同金额重复不构成冲突。 5. `PurchaseResultPayload` 仅在金额非 null 时携带该字段;Server 对合法非 null 金额已有落库路径。同设备其他成功订单能正常带回金额。 6. 样例成功结束,无对应失败现场快照。**尚不能确定这一次属于加载慢、不可见、标签拆分、文字变化还是金额冲突。** 本单针对已确认的“金额缺失无补读机会”做有界改善,不宣称重试必然解决该样例。 7. 当前分析只读核验了数据链路与代码,未重现真实页面时序,也未执行本单新增测试。后续先写合成失败用例再实现。 ## 目标与非目标 目标:第一次已确认订单创建、只缺订单金额时,停留当前页面,延迟约 1 秒进行最多一次额外只读采样;获取成功则补上金额,否则保持原结果。 非目标: - 不重新打开商品、不遍历“我的订单”、不重下单、不付款、不新增点击/返回/拉前台/滑动。 - 不把下单前单价或单价×数量当作订单应付总额,不推断是否付款。 - 不新增金额必填门禁;不因金额缺失把成功订单改成 failed 或 order_result_unknown。 - 不扩大金额文案/币种/节点拼接支持,不改已有“应付”解析和有效性规则。 - 不改 Server/Web、API、权限、业务库或 Android SQLite 结构,不改 SYB 回填逻辑,不补写历史数据。 - 不调整既有支付页等待、单号/时间搜索、租约、任务串行及状态机,不引入通用重试框架或可配置项。 ## 最小流程设计(非 UI) 设计依据:用户本轮确认的最小方向及 Claude #186,确认日期 2026-10-14。无界面变化,不要求 UI 原型;本正文作为待实施的流程和验收证据。 1. 正常核单按原流程进行。首次取得合法 `PurchaseOrderEvidence` 时保存首次订单号、时间和已累积的 labels。 2. **首次金额非 null(包括 0)时原样返回**:不得新增 pause 或 capture。 3. 首次金额为 null 时,只走独立补读步骤:约 `1000ms` pause,再 `capture` 一帧,最多一次。不重新进入原核单主循环,以免触发原循环的入口点击、返回或定期上滑路径。实际额外耗时还包括 capture,不承诺严格 1 秒墙钟上限。 4. 补读帧必须来自 PDD 包且具备既有订单或待付款上下文;微信、系统应用选择页、无订单上下文的纯支付页、陌生/空窗口直接忽略。沿用既有“订单/待付款证据优先于复用支付 Activity 名称”的判定,不新增导航动作。 5. 合格帧的可见 labels 并入**同一订单读取过程的原累积集合**,再解析一次。仅当并集能解析、订单号与首次相同、且金额为唯一合法值时采用新金额;最终订单号和下单时间始终使用首次已确认值。补读帧单独缺少重复显示的订单号时,仍依赖同一过程的累积证据,不另创猜测匹配。 6. 并集出现其他订单号、多订单号、不同金额、溢出或其他解析失败时,保留首次订单号与时间,金额仍为空。不得只用第二帧覆盖第一帧,从而消除已经观察到的金额冲突。 7. 补读无效或常规采样/解析异常时返回首次成功证据;不得调用会将任务抛成失败的 `pageProblem`,不得把已确认订单降级。保持既有线程取消/进程终止语义,不通过吞掉致命错误伪造完成。 8. 复用原结果上报路径一次提交,不新增 result 请求或 attempt。 ## 轻量诊断 若复用现有 `panelDiagnostic` 可实现,补读仍无金额时记录结构化分类与计数,例如 `no_payable_label`、`conflict`、`invalid`,及补读页面被忽略/读取异常;不得输出标签原文、价格、订单号、地址或控件树,不新增表/接口/上传管道。 分类必须与实际判定一致:缺少符合现有规则的金额,不得伪装成已证明的页面加载慢;未匹配文案也不能仅凭 null 就断言格式非法。诊断失败不得影响首次订单事实。仅采用必要的小范围诊断,不为分类重构整个金额解析器。 ## 依赖、子项目与并行边界 - 前置:最新 main 已有 #325/#326/#365 的订单结果和可选金额链路;本轮确认存在,实施时复核。 - 交付单元:Android 核单返回处的小范围逻辑与相应单元测试;必要时私有辅助函数。数据模型与接口不变。 - 与修改 `PurchaseLiveAutomation.readOrderResult`、订单证据或金额解析的工单不可并行编辑;无代码依赖的其他模块可并行,但本单不分派额外范围。 - 正式实施按仓库规则创建单独 issue worktree;当前未创建开发分支或 worktree。 ## 验收与测试 - [ ] 首次已有唯一订单号、时间和合法金额:capture 次数、pause 总时长、返回字段及原流程均不变;0 元同样不补读。 - [ ] 首次只缺金额,约 1 秒后的唯一补帧出现合法金额:补齐金额,订单号和时间保持首次值;恰好增加一次 pause 和一次 capture。 - [ ] 第二帧仍无金额:保持 `order_created` 所需证据,金额为空,不循环。 - [ ] 第二帧出现不同/多个订单号:忽略新金额,保留首次订单事实。 - [ ] 第二帧是微信、系统选择页、纯支付页、陌生包或空窗口:忽略,不触发返回、点击、前台恢复或滑动,不降级为 unknown。 - [ ] 首次累积金额冲突,补帧只剩其中一个金额:冲突仍存在,不猜值;同值父子重复则正常去重。 - [ ] 金额解析无效/溢出、补读常规异常、诊断异常:保留首次订单号和时间及原成功结果,不造成二次下单。 - [ ] 首次没有取得有效订单证据:不触发该补读机制,原等待/失败路径不变。 - [ ] 用 mock driver 断言补读路径不增加 click/back/swipe/bring-to-foreground,不创建额外 attempt/result 上报。 - [ ] 先执行受影响单测观察预期失败,再最小实现、全套 Android 单测及 APK 构建;记录实际命令、结果、提交及未验证项。 - [ ] 真机行为/缺金额改善比例若未验证,明确标注,不用合成测试声称线上成功率提升。覆盖安装和真实采购须另行授权。 - [ ] 实施、必要文档、提交推送与证据集中回写后停在待用户验收,不自行关闭。 ## 风险、回退与授权 采购流程行为变化属于高风险,用户当前只要求建单。实施和真机操作按各自范围取得授权后进行。此改动只缓解金额迟到,不保证解决未识别文案或跨节点页面结构;不能据此承诺历史样例必然恢复。 保留首个成功结果是主要回归边界。回退为撤销本单独立补读逻辑;不涉及数据迁移、历史清理或订单撤销。部署/重启/真机执行不属于本单建单授权。 ## 长期文档影响 实施确认后更新 Wiki `Business-Rules-and-Glossary` 的下单后核单金额读取流程:一次有界补读、首次事实保留、金额可空及无新增动作。若现有 API 契约仅描述字段和可选性,无需制造接口变化;实施时确认文档一致性。按 Wiki-first 在线修改、回读 revision,执行一轮 sync 与 sync --check 并提交镜像。 本次只建单,不提前修改 Wiki 宣称功能已实现,不创建任务归档或本地第二事实来源。
Author
Owner

2026-10-14 Claude Code:开始实施

用户回复「你安排subagent用sonnet做#392和#393,然后合并到main,勾选最新apk后安装到测试机」。

  • worktree D:/OPC/goauto-worktrees/issue-392,分支 fix/392-order-amount-reread,基线 origin/main 9f918b0(已含 #388、#390、#391)。
  • 由 Sonnet 子 Agent 按正文实施,主 Agent 审查后合并 main。本单不改版本号,与 #393 一起以 0.9.75(88)构建。
  • 本次授权包括实施、合并 main、构建 APK 并安装到测试机。采购机装机、服务端发布和真机下单不在本次授权内。
### 2026-10-14 Claude Code:开始实施 用户回复「你安排subagent用sonnet做#392和#393,然后合并到main,勾选最新apk后安装到测试机」。 - worktree `D:/OPC/goauto-worktrees/issue-392`,分支 `fix/392-order-amount-reread`,基线 `origin/main` `9f918b0`(已含 #388、#390、#391)。 - 由 Sonnet 子 Agent 按正文实施,主 Agent 审查后合并 main。本单不改版本号,与 #393 一起以 0.9.75(88)构建。 - 本次授权包括实施、合并 main、构建 APK 并安装到测试机。采购机装机、服务端发布和真机下单不在本次授权内。
ila referenced this issue from a commit 2026-10-14 11:38:44 +08:00
Author
Owner

2026-10-14 Claude Code:已合并 main 并装测试机(待验收)

  • 实施:Sonnet 子 Agent 提交 bf8f0a1(PurchaseLiveAutomation.kt +62/−1,测试 +193/−4),主 Agent 审查后合并 main d1094a4(--no-ff),随后合并 #393(6a9c823)。
  • 实现:readOrderResult 首次取得订单证据但金额为空时,调用独立的 rereadMissingOrderAmount。做一次 pause(ORDER_AMOUNT_REREAD_DELAY_MS=1000) 和一次 capture,帧须是 PDD 页面且有订单或待付款上下文;与累积文字取并集后重新解析,订单号相同且金额非空才补上,否则返回首次结果。补读不点击、不返回、不滑动、不调用 pageProblem。InterruptedException 恢复中断标志后返回首次结果,CancellationException 继续抛出。诊断 orderAmountReread;outcome=... 只记录枚举值。
  • 测试:新增 11 个 reread* 用例,覆盖验收条目;去掉实现时,其中 9 个按预期失败。4 个原有测试的 capture 次数各 +1,原因是样例订单页没有「应付」金额,会多补读一次,这是本单要求的新行为。
  • 验证:在合并结果上运行 Android testDebugUnitTest,866 个用例、0 失败;assembleDebug 通过;go test -count=1 ./app/goauto/purchase/... ./cmd/migrate/... 通过。
  • APK:合并结果构建的 0.9.75 / 88,路径 D:/OPC/goauto-worktrees/merge-370-380/android/app/build/outputs/apk/debug/app-debug.apk,SHA256 0fe5fd2d190ccb71be0ede28a61b51fbae7890f5e1d62f4e3b9b684dd26d1ec9(采购机证书 bf86d746…766dec),包含 #388、#390、#391、#392、#393。
  • 测试机:按授权,用测试机密钥 ~/.android/debug.keystore 重新签名(SHA256 6a0e3297…82192c4b,证书 3eab2527…c7c4f6,与已装版本一致)。在 192.168.0.6:38593(序列号 3B668T01GF400000,前台为系统设置、没有执行中的任务)上覆盖安装,11:34:40 起为 0.9.75 / 88,没有卸载。
  • Wiki:Business-Rules-and-Glossary 新增 #392 一节,revision a36404c6e017b5b3661fe44cbfaf3c334147a0a8;镜像提交 df640ec,sync --check 通过。
  • 未验证:真机核单效果,以及缺金额比例能否改善。测试机连接的本地服务端版本较旧,见 #393 评论。
### 2026-10-14 Claude Code:已合并 main 并装测试机(待验收) - 实施:Sonnet 子 Agent 提交 `bf8f0a1`(`PurchaseLiveAutomation.kt` +62/−1,测试 +193/−4),主 Agent 审查后合并 main `d1094a4`(`--no-ff`),随后合并 #393(`6a9c823`)。 - 实现:`readOrderResult` 首次取得订单证据但金额为空时,调用独立的 `rereadMissingOrderAmount`。做一次 `pause(ORDER_AMOUNT_REREAD_DELAY_MS=1000)` 和一次 `capture`,帧须是 PDD 页面且有订单或待付款上下文;与累积文字取并集后重新解析,订单号相同且金额非空才补上,否则返回首次结果。补读不点击、不返回、不滑动、不调用 `pageProblem`。`InterruptedException` 恢复中断标志后返回首次结果,`CancellationException` 继续抛出。诊断 `orderAmountReread;outcome=...` 只记录枚举值。 - 测试:新增 11 个 `reread*` 用例,覆盖验收条目;去掉实现时,其中 9 个按预期失败。4 个原有测试的 capture 次数各 +1,原因是样例订单页没有「应付」金额,会多补读一次,这是本单要求的新行为。 - 验证:在合并结果上运行 Android `testDebugUnitTest`,866 个用例、0 失败;`assembleDebug` 通过;`go test -count=1 ./app/goauto/purchase/... ./cmd/migrate/...` 通过。 - APK:合并结果构建的 0.9.75 / 88,路径 `D:/OPC/goauto-worktrees/merge-370-380/android/app/build/outputs/apk/debug/app-debug.apk`,SHA256 `0fe5fd2d190ccb71be0ede28a61b51fbae7890f5e1d62f4e3b9b684dd26d1ec9`(采购机证书 `bf86d746…766dec`),包含 #388、#390、#391、#392、#393。 - 测试机:按授权,用测试机密钥 `~/.android/debug.keystore` 重新签名(SHA256 `6a0e3297…82192c4b`,证书 `3eab2527…c7c4f6`,与已装版本一致)。在 `192.168.0.6:38593`(序列号 `3B668T01GF400000`,前台为系统设置、没有执行中的任务)上覆盖安装,11:34:40 起为 0.9.75 / 88,没有卸载。 - Wiki:Business-Rules-and-Glossary 新增 #392 一节,revision `a36404c6e017b5b3661fe44cbfaf3c334147a0a8`;镜像提交 `df640ec`,`sync --check` 通过。 - 未验证:真机核单效果,以及缺金额比例能否改善。测试机连接的本地服务端版本较旧,见 #393 评论。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#392