Skip to content

feat(billing): durable refund retries and reconciliation - #5

Merged
YunfanGoForIt merged 8 commits into
mainfrom
codex/refund-compensation-20261016
Oct 20, 2026
Merged

YunfanGoForIt merged 8 commits into
mainfrom
codex/refund-compensation-20261016

Conversation

@OnePlus-X-code

@OnePlus-X-code OnePlus-X-code commented Oct 16, 2026 •

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

Codex 辅助设计、实现和验证,待维护者人工审阅;人工确认项保持未勾选。

📝 变更描述 / Description

BillingSession 的异步退款曾在设置内存 refunded 标记后分别退资金来源和 Key,最终失败只记日志。现在退款意图持久化后才交给异步 worker;钱包/订阅原始预扣/追加预扣与 Key 在一个 SQL 事务中退款,同时写幂等完成标记。缓存失效单独持久化为 cache_pending,重试不会再次入账。

新增一张不含 Key 明文的退款凭据表,复用原订阅幂等记录和现有 SystemTask 的调度、租约、失败记录及通知通道。失败采用持久化退避持续重试;Root 可分页对账、审阅重试或确认已核对的结果;未完成/结果不明记录受清理保护。可退款扣款直接写 SQL,避免进程内批量队列丢失原扣款而退款仍被恢复。

预扣前留下审计锚点,正常结算与退款终态分开;结果不明的预扣/结算不能按超时自动退款,保留并告警供人工核对。范围、状态契约、操作接口、清理及回滚约束见设计与测试记录。

以 PR #3 冻结提交为基线,独立分支和差异,不向 PR #3 追加提交,也不混入 Auto 标记 PR #4。基础提交进入 main 后可调整 base。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix)
  • ✨ 新功能 (New feature)
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • 用户要求的独立退款补偿专项,无关联 Issue;设计边界来自前轮实际故障注入。

✅ 提交前检查项 / Checklist

📸 运行证明 / Proof of Work

  • 最终本地完整后端:34 个有测试的包通过,1,230 个叶子用例、1,318 条父/子 pass 事件、12 个显式跳过、0 失败。完整 vet/build 通过。
  • 隔离 PostgreSQL 16.14:77 个叶子用例、85 条父/子 pass 事件,0 失败/跳过,涵盖退款、支付及商品/Key 合同。
  • 真实 SQL COMMIT 已成功但客户端确认被协议代理丢弃:客户端收到错误,重试后钱包和 Key 均只恢复一次。结果不明的结算另有持久化目标与重复执行保护。
  • 退款 SQL 中的 Key/标记失败一起回滚;缓存阶段失败不再入账;丢弃会话后由 SQL 恢复;批量更新开关开启时原扣款仍持久化。
  • 连续失败、Root 对账权限、后台失败告警、人工依据和记录清理保护均有回归测试。
  • 退款最终失败不再永久终止;未知预扣/结算结果仍需人工核对,不能自动猜测或批量退款历史 consumed 记录。
  • 代码提交 62e306126 的 CI:完整后端与 relaykit、三个 PostgreSQL race job 全部通过;其后只有验收文档补录。前端仍为 base/head 各 175/3,未混入独立 PR fix(keys): restore Auto badge presentation contract #4 的 UI 修复;PR fix(keys): restore Auto badge presentation contract #4 前端 179/179 且 CI 全绿。
  • 最终提交 34b6db14f 的 CI 再次确认:完整后端、PG model/service/controller + race 全部通过;前端仍为已由 fix(keys): restore Auto badge presentation contract #4 修复的三个相同基线失败。
  • 未验证 MySQL 实例、生产快照、外部通知真实投递、真实机器断电和真实支付;未知预扣/结算结果保留人工对账路径。

保持 Draft,不合并、不部署;新表仅在隔离测试库迁移。未来回滚前需完成/导出非终态退款,不得直接让旧版本忽略待补偿状态。

@YunfanGoForIt
YunfanGoForIt force-pushed the codex/refund-compensation-20261016 branch from 34b6db1 to 15e21ae Compare October 20, 2026 16:40
@YunfanGoForIt
YunfanGoForIt changed the base branch from codex/architecture-refactor-20261016 to main October 20, 2026 16:40
…-quota pre-consume

Sessions whose pre-consume truncated to zero had no durable refund receipt;
a later Reserve debited wallet and key quota that Refund then silently
skipped. Create the receipt before debiting so the durable worker can
always recover the funds.
…tion

Receipts inside their normal backoff window made every periodic run report
failure and blocked succeeded-receipt cleanup. Count only due receipts.
@YunfanGoForIt
YunfanGoForIt marked this pull request as ready for review October 20, 2026 16:56
@YunfanGoForIt

Copy link
Copy Markdown

维护者处理记录(2026-10-21):

  1. Rebase:原 base 分支 codex/architecture-refactor-20261016 已经 PR refactor: unify subscription reservations and wallet quota accounting #3 合入 main,本分支已 rebase 到最新 main 并改 base 为 main;CI 矩阵冲突取并集(保留 TestBigfish 同时加入 TestBillingRefund 系列)。
  2. 评审:按资金安全/并发/三库兼容/JSON 包装/SystemTask 五个维度完成评审,发现并修复两项:
    • 57e0a6da 修复 Major:预扣截断为 0 的会话无持久凭据,后续 Reserve 真实扣款在失败时被静默跳过(该退不退)。现在 Reserve 在扣款前补建凭据,含回归测试。
    • 8f87b578 修复 Minor:正常退避窗口内的凭据被计为待办,导致周期任务每分钟误报且 succeeded 凭据清理永不执行。现在只统计到期未推进的凭据,含回归测试。
  3. 其余 minor/nit(凭据 RequestID 校验、6h 告警阈值、审计日志 reason 等)记录为后续跟进项,不阻塞合并。

本地验证:go build ./...、go vet、model/service 退款测试套件全部通过(SQLite);PostgreSQL 由 CI 矩阵验证。此修复由 AI 辅助完成,已经维护者核对。

@YunfanGoForIt
YunfanGoForIt merged commit 7b0779a into main Oct 20, 2026
5 checks passed
@YunfanGoForIt
YunfanGoForIt deleted the codex/refund-compensation-20261016 branch October 20, 2026 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants