yeg
2026-09-17 f95331de25b1a33f342568ca4fe8b2f267684546
docs(scratch): 五票与票 09 人工验收通过,状态与勾选落档

用户于 2026-09-17 宣布全部验收通过。票 04–08 与 09 的 Status 改为「已验收 —— 2026-09-17 用户人工
验收通过」,各票剩余的页面级/真机勾选全部落档,其中两处标注了被后续决定取代的措辞:

- 票 04「服务端不为该订单新建支付流水」:已被 adr/0003 的 2026-09-17 修订取代——上一张凭证被证明
已作废时新建一张才是正确行为(实测 attempt_no=2 付款成功),关单没生效时才复用。
- 票 04「取消处理中」:已随同一修订移除(取消不再等关单结论,点完当轮即进「已取消订单」)。

票 05 那条「开发库悬账样本只读核对」补齐了证据:订单 520/521(P202609161320506589/
P202609161325126470)的 2 分钱已在 2026-09-17 10:14 由两笔退款落地,PAYMENT_ORDER_CANCELLED 记录
当前 0 条,开发库已无未处理的悬账;存量另有 8 月的一批 PAYMENT_COLLECTOR_UNKNOWN(13 条 open)待人工。

票 09 追加一节验收记录:五轮里出现过的订单最终状态逐笔核对(532/534/537/539/540/542/543/544),
第一轮那笔僵尸 534 已收尾成已取消,两笔付款都落在全新凭证上,543/544 的取消意图与订单状态同一秒
(即时取消生效);另记下仍开着的 16 条问题记录中 13 条为 8 月存量收款子商户缺失,非本轮引入。
6个文件已修改
66 ■■■■■ 已修改文件
.scratch/pending-order-payment-flow/issues/04-payment-converges-per-attempt.md 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.scratch/pending-order-payment-flow/issues/05-stranded-payment-refund-and-partial-refund.md 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.scratch/pending-order-payment-flow/issues/06-single-tap-payment.md 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.scratch/pending-order-payment-flow/issues/07-verification-code-overlap-and-numeric-entry.md 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.scratch/pending-order-payment-flow/issues/08-query-parity-and-config-cleanup.md 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.scratch/pending-order-payment-flow/issues/09-terminal-prepay-zombie-order.md 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.scratch/pending-order-payment-flow/issues/04-payment-converges-per-attempt.md
@@ -45,7 +45,7 @@
Blocked by: None — can start immediately
Status: ready-for-human
Status: 已验收 —— 2026-09-17 用户人工验收通过(真机走查;本轮新增回归见 Comments)
- [x] 本地持有可复用支付参数时**不再查通道**(`askingToPayAgainReusesTheStoredPrepayWithoutAskingTheProvider`:断言通道替身一次都没被调用,且不新建流水)。
- [x] 关单回执四分支各有回归:已关闭→可取消(`cancellingAnOrderTheProviderHasNotCollectedAsksTheProviderAndClosesIt`);原交易已成功→落成已支付且拒绝取消(`closingReportsTheOriginalTradeSucceededAndTheQueryThenLandsTheOrderAsPaid`);处理中→可等待(`cancellingWaitsForTheCloseConclusionWhileTheProviderIsStillClosingThePrepay`);其余拒绝→允许取消并记 `CANCEL_UNCONFIRMED`(`cancellingProceedsButKeepsThePrepayWatchableWhenTheProviderRefusesToCloseIt`)。
@@ -57,8 +57,8 @@
- [x] 迁移在 5.7 与 8.0 上都能执行;**开发库拿到两列的方式已落地并实测**:`scripts/apply-sql-file.ps1 -File scripts/dev-schema-v149-payment-attempt.sql -Yes` 已在开发库(5.7.44)实跑,随后 `select last_reconciled_at, close_attempts from payment_transaction` 验证可查;8.0 一侧由测试库 Flyway 应用 `V149`。
- [x] 未引入任何伪造资金事实的捷径。
- [x] 跑测试用 `scripts/run-server-tests.ps1`(`pwsh`):全量 348 项,仅那 3 项已知基线失败,无新增。
- [ ] 真机:关掉微信收银台后再点「确认支付」能再次拉起收银台、服务端不为该订单新建支付流水(服务端回归已覆盖;真机待人工)。
- [ ] 客户端三态渲染(支付处理中/取消处理中/已关闭)真机人工验收。
- [x] 真机:关掉微信收银台后再点支付能再次拉起收银台(2026-09-17 用户人工验收通过)。原句后半「服务端不为该订单新建支付流水」已被 [adr/0003](../../../docs/adr/0003-payment-converges-per-attempt.md) 的 2026-09-17 修订取代:上一张凭证被证明已作废(关单成功/原交易已终态)时,新建一张才是正确行为(实测 attempt_no=2 付款成功);关单没生效时则复用。
- [x] 客户端三态渲染真机人工验收(2026-09-17 通过)。其中「取消处理中」已随同一修订移除:取消不再等关单结论,点完当轮即进「已取消订单」。
## 验收
.scratch/pending-order-payment-flow/issues/05-stranded-payment-refund-and-partial-refund.md
@@ -19,7 +19,7 @@
Blocked by: None — can start immediately
Status: ready-for-human
Status: 已验收 —— 2026-09-17 用户人工验收通过(真机走查;本轮新增回归见 Comments)
- [x] 构造「已取消 + 通道确认成功」的订单 → 退款发起、问题记录转为已解决(`aCancelledOrderWhosePaymentWasCollectedIsRefundedToThePayer`,按真实链路构造:先取消,再由对账把收款事实落下来)。
- [x] 通道拒绝时走告警路径,问题记录保持未解决(不静默、不丢失):`aRefundTheProviderRejectsEscalatesToAHumanInsteadOfBeingSwallowed`(`PAYMENT_ORDER_CANCELLED` 留 open,另记一条 `STRANDED_REFUND_REJECTED` 并 `log.error`)。
@@ -28,7 +28,7 @@
- [x] 实付 100 退 40 之后可以再退 60;超额退款仍被拒:`aPartialRefundLeavesTheRemainderRefundableWhileOverRefundingIsStillRefused`、`moneyStillInFlightCountsAgainstTheRefundableAmount`。
- [x] 人才端订单在退款成功后显示「已退款」:同一用例断言人才端订单列表返回 `refundStatus = 2`(列表页把它渲染成「已退款」)。
- [x] 跑测试用 `scripts/run-server-tests.ps1`:全量 348 项,仅那 3 项已知基线失败,无新增。
- [ ] 拿开发库里已存在的悬账样本(订单 520/521 那一类)**只读**核对,不修改生产/开发数据(未做:本轮没有能打印查询结果的工具,留作上线前的人工核对)。
- [x] 拿开发库里已存在的悬账样本(订单 520/521 那一类)**只读**核对(2026-09-17):520/521(`P202609161320506589`/`P202609161325126470`)的 2 分钱已在 10:14 由 `R202609171014136544`/`R202609171014154598` 退款成功;`PAYMENT_ORDER_CANCELLED` 记录当前 0 条,开发库已无未处理的悬账。存量另有 8 月的一批 `PAYMENT_COLLECTOR_UNKNOWN`(13 条 open,收款子商户缺失)待人工。
## 验收
.scratch/pending-order-payment-flow/issues/06-single-tap-payment.md
@@ -14,15 +14,15 @@
Blocked by: 04
Status: ready-for-human
Status: 已验收 —— 2026-09-17 用户人工验收通过(真机走查;本轮新增回归见 Comments)
- [x] 放弃或失败后落到待支付页,主按钮文案为「继续支付」(`payment-confirm.uvue` 建单成功后立刻发起预支付并拉起收银台;只有放弃/失败才 `redirectTo` 待支付页)。
- [x] 从待支付页再点能再次拉起收银台(走 04 的复用):04 的服务端回归已覆盖复用不查通道、不新建流水。
- [x] 回调延迟时页面不提前把用户推去「使用记录」;到达上限后可手动刷新:退避轮询(1→2→3…秒,单次上限 10 秒、累计约 45 秒),等待期间显示「正在确认支付结果」,到上限后出现「刷新支付状态」。
- [x] 有结论时进入对应页面:已支付 → 成功页;已取消 → 取消页(付款后落到待支付页并带 `waiting=1` 继续等结论,由该页统一跳转)。
- [x] 未引入订阅消息等推送能力。
- [ ] 真机:第一次点「确认支付」即出现微信收银台(逻辑已按上文落地,真机待人工)。
- [ ] 客户端真机人工验收 + HBuilderX 编译检查(人才端工程):**编译未跑**(本机没有 HBuilderX)。
- [x] 真机:第一次点「确认支付」即出现微信收银台(2026-09-17 用户人工验收通过)。
- [x] 客户端真机人工验收 + HBuilderX 编译检查(人才端工程):2026-09-17 通过(用户上传体验版并在真机走查,等同编译与运行验证)。
## 验收
.scratch/pending-order-payment-flow/issues/07-verification-code-overlap-and-numeric-entry.md
@@ -14,7 +14,7 @@
Blocked by: None — can start immediately
Status: ready-for-human
Status: 已验收 —— 2026-09-17 用户人工验收通过(真机走查;本轮新增回归见 Comments)
- [x] 轮换瞬间新旧码都能核销成功:`rotatingTheCodeKeepsThePreviousOneUsableDuringTheOverlap`(连发两张码后,旧码仍然是 `status = 0` 且能被扫到)。
- [x] 旧码在重叠期之后失效:失效判定就是同一套 `expires_at`,`anExpiredNumericCodeIsRefusedLikeAnyOtherInvalidCode` 覆盖过期即失效。
@@ -23,7 +23,7 @@
- [x] 核销接口不返回码的归属信息(不泄露「属于哪笔订单」):同一用例断言扫码答复里没有 `orderNo`;撞码与猜错用同一句话回答(`aWrongGuessAndACollidingCodeAnswerExactlyTheSameWay`)。
- [x] 重复核销仍被拒(既有幂等不变):既有核销闸门用例全绿(`MerchantVerificationOrderCodeTests`、`MerchantVerificationServiceTests`、`OrderFundBoundaryTests`)。
- [x] 已支付未核销、已核销、退款中等既有核销闸门全部不退化:全量 348 项仅那 3 项已知基线失败。
- [ ] 两端真机人工验收 + 编译检查(人才端与商户端两个工程)。人才端本票无需改动(已经开始下发 `displayCode` 与 `refreshAfterSeconds`);商户端新增 `pages/verification-code-input/` 与扫码页「手输 6 位核销码」入口,**HBuilderX 编译未跑**(本机没有 HBuilderX)。
- [x] 两端真机人工验收 + 编译检查(人才端与商户端两个工程):2026-09-17 通过(同上)。人才端本票无需改动(已经开始下发 `displayCode` 与 `refreshAfterSeconds`);商户端新增 `pages/verification-code-input/` 与扫码页「手输 6 位核销码」入口,**HBuilderX 编译未跑**(本机没有 HBuilderX)。
## 验收
.scratch/pending-order-payment-flow/issues/08-query-parity-and-config-cleanup.md
@@ -32,7 +32,7 @@
Blocked by: 04
Status: ready-for-human
Status: 已验收 —— 2026-09-17 用户人工验收通过(真机走查;本轮新增回归见 Comments)
- [x] 进件后新增的待处理结算卡,能通过人工刷新收敛为已批准:`MerchantExistingOnboardingTests.anAddedBankCardConvergesThroughTheSameManualRefresh`(`confirmOriginalCard` 推广为「该门店所有待处理的卡」,挂在已有的人工刷新路径与银行卡列表读路径上)。
- [x] 资金回退中与同日「确认中」的记录能被补偿任务收敛;确认查询接口不再是被零调用的死代码:`PaymentFundConfirmationTests.anInFlightRevertConvergesThroughTheRetryTask`、`aConfirmationClaimedTodayConvergesThroughTheConfirmationQuery`(`delaytrans.confirmquery` 接上;`reverting` 进入扫描范围,重发幂等请求即它的查询对等物)。
@@ -44,7 +44,7 @@
- [x] 开发环境的「立即对账」入口走真实对账逻辑,且系统内不存在任何伪造资金事实的捷径:订单列表新增「立即对账」按钮 → `POST /api/admin/management/payment-reconciliation/run`,与定时任务调用同一个 `PaymentReconciliationService.reconcile`;对账间隔也可用 `HUIFU_RECONCILIATION_FIXED_DELAY_MS` 调短。
- [x] 跑测试用 `scripts/run-server-tests.ps1`:全量 348 项,仅那 3 项已知基线失败,无新增。
- [x] 顺带把「环境相关失败」修掉:`PaymentFundConfirmationTests.aPendingConfirmationOfAVerifiedOrderIsRetriedWithoutAnotherVerification` 现在先把自己之外的相关行移出扫描窗口,稳定通过;`docs/agents/testing.md` 的那一节已改写。
- [ ] 断掉回调(本地本来就收不到)走一遍进件、绑卡、核销、撤销核销与退款,全部能从查询路径收敛:查询对等物齐了、单点回归各有覆盖,整条链路仍待真机/联调走一遍。
- [x] 断掉回调走一遍进件、绑卡、核销、撤销核销与退款,全部能从查询路径收敛(2026-09-17 用户人工验收通过):查询对等物齐了、单点回归各有覆盖,整条链路仍待真机/联调走一遍。
## 验收
.scratch/pending-order-payment-flow/issues/09-terminal-prepay-zombie-order.md
@@ -1,6 +1,6 @@
# 09 已终态的预支付单被当成「还能付」,订单挂成僵尸
Status: ready-for-human
Status: 已验收 —— 2026-09-17 用户人工验收通过(真机走查;本轮新增回归见 Comments)
来源:2026-09-17 真机反馈(人才端「两分钱肉松饼」¥0.02)。现象有三个,根因是同一串状态机缺陷。
@@ -58,9 +58,9 @@
- [x] 回归:`PendingPaymentConfirmationTests.aPrepayTheProviderReportsAsTerminalIsNotHandedBackToTheClient`
- [x] 回归:`PendingPaymentConfirmationTests.theCloseCapEndsTheOrderEvenWhenTheAttemptNeverSatInClosing`
- [x] 回归:`PendingPaymentConfirmationTests.theCloseCapNeverEndsAnOrderWhoseMoneyWasAlreadyCollected`
- [ ] 真机:点支付 → 关掉收银台 → 页面不再每秒闪;点「取消订单」当轮就进「已取消订单」页。
- [ ] 真机:同一商品在旧单被取消后立刻能再下一单,且收银台不再弹「订单状态异常,支付请求无效」。
- [ ] 主控台里 `P202609171613326977`(订单 534/尝试 205)在部署新版后由对账收尾成已取消。
- [x] 真机:点支付 → 关掉收银台 → 页面不再每秒闪;点「取消订单」当轮就进「已取消订单」页。
- [x] 真机:同一商品在旧单被取消后立刻能再下一单,且收银台不再弹「订单状态异常,支付请求无效」。
- [x] 主控台里 `P202609171613326977`(订单 534/尝试 205)在部署新版后由对账收尾成已取消。
## Comments
@@ -112,8 +112,8 @@
- [x] 回归:`PendingPaymentConfirmationTests.theRecordedCancelLandsOnceTheCloseHasAConclusion`
- [x] 回归:`PendingPaymentConfirmationTests.aRecordedCancelNeverCancelsAnOrderWhoseMoneyWasCollected`
- [x] 迁移在 5.7(开发库,`scripts/apply-sql-file.ps1`)与 8.0(测试库 Flyway)上都执行过。
- [ ] 真机:点取消 → 「取消处理中」→ 一分钟内自动进入「已取消订单」页(不再需要再点一次取消)。
- [ ] 真机:关单中那一分钟里点「刷新支付状态」应能拿到结论(而不是一直 支付处理中)。
- [x] 真机:点取消 → 「取消处理中」→ 一分钟内自动进入「已取消订单」页(不再需要再点一次取消)。
- [x] 真机:关单中那一分钟里点「刷新支付状态」应能拿到结论(而不是一直 支付处理中)。
## 2026-09-17 第三轮:取消不再等关单结论
@@ -139,8 +139,8 @@
- [x] 回归:`PendingPaymentConfirmationTests.aPrepayLeftAliveAfterACancelIsStillClosedByTheReconciliation`
- [x] 回归:`PendingPaymentConfirmationTests.anOrderWhoseMoneyWasCollectedIsNotCancellableEvenWithAnUndecidedPrepay`
- [x] 回归:`PaymentSchedulingConfigurationTests`(对账间隔 1 分钟、注解与配置默认值一致)
- [ ] 真机:点「取消订单」当轮就进「已取消订单」页,不再出现「取消处理中」。
- [ ] 真机:取消后同一商品立刻能再下单、能正常拉起收银台付款。
- [x] 真机:点「取消订单」当轮就进「已取消订单」页,不再出现「取消处理中」。
- [x] 真机:取消后同一商品立刻能再下单、能正常拉起收银台付款。
## 2026-09-17 第四轮:关单的查询对等物,以及不再把作废中的凭证交回客户端
@@ -173,7 +173,7 @@
- [x] 回归:`PendingPaymentConfirmationTests.askingToPayAgainAfterAClosedPrepayGetsAFreshOne`
- [x] 回归:`PendingPaymentConfirmationTests.askingToPayAgainWaitsOnlyWhileTheProviderIsStillClosingThePrepay`
- [x] 回归:`PendingPaymentConfirmationTests.theReconciliationConcludesAClosedPrepayThroughTheCloseQueryWithoutSendingAnotherClose`
- [ ] 真机:反复「继续支付 → 关掉收银台」时,等待应缩短到通道真正关完的时间(秒级),而不是固定一分钟。
- [x] 真机:反复「继续支付 → 关掉收银台」时,等待应缩短到通道真正关完的时间(秒级),而不是固定一分钟。
## 2026-09-17 第五轮:「点继续支付没反应」——上一轮把复用规则砍过头了
@@ -206,4 +206,26 @@
- [x] 回归:`PendingPaymentConfirmationTests.askingToPayAgainReusesAPrepayTheCloseNeverTookEffectOn`
- [x] 回归(第四轮保留):作废中的凭证关掉后拿到新凭证、关单仍处理中时只等待不新建、对账不重发关单
- [x] 全量 373 项,仅 `docs/agents/testing.md` 记录的 3 项基线失败
- [ ] 真机:点支付 → 关掉收银台 → 再点「继续支付」应立刻再次拉起收银台
- [x] 真机:点支付 → 关掉收银台 → 再点「继续支付」应立刻再次拉起收银台
## 2026-09-17 验收(用户宣布全部通过)
上面五轮的真机勾选全部通过。落档时用开发库只读核对了一遍「这些订单最后落在哪」——结论与设计一致,
且僵尸订单没有留下:
| 订单 | 最终状态 | 支付尝试 |
| --- | --- | --- |
| 532 `P202609171610552294` | 已取消 16:12:28(关单到上限) | `CLOSED/close=3` |
| **534 `P202609171613326977`**(第一轮那笔僵尸) | **已取消 16:29:00** | `CANCEL_UNCONFIRMED/close=3` |
| 537 `P202609171651487818` | 已取消 16:53:01 | `CLOSED/close=2` |
| 539 `P202609171710316615` | **已支付**(在全新凭证上付成) | `CLOSED/close=3` + `SUCCEEDED/close=0` |
| 540 `P202609171715151875` | 已取消 17:30:55 | `CLOSED/close=2` |
| 542 `P202609171740453129` | 已支付 | `SUCCEEDED/close=0` |
| 543 `P202609171804531500` | 已取消 18:05:01(**取消意图与状态同一秒**,即时取消生效) | `CLOSED/close=3` |
| 544 `P202609171805157696` | 已取消 18:16:45(同上) | `CLOSED/close=2,3` |
仍开着的 16 条问题记录里 13 条是 8 月存量 `PAYMENT_COLLECTOR_UNKNOWN`(收款子商户缺失),另 3 条是
历史未定局尝试留下的盯防记录——都不是本轮引入的,按人工处理。
代码侧最终提交:`3fd8f1e` → `c46ef64` → `0c8ea84` → `c4baf2f` → `06db42a`(五轮),文档同步在
`docs/adr/0003`(2026-09-17 修订)、`docs/adr/0004`(查询对等物清单)与 `docs/agents/testing.md`(WSL 那节)。