Found 2026-09-05 in wave-1B E2E on the deploy preview of #1422 (union of the merged train). Reproduced on a throwaway org (LearnPro Academy cmqb27jge06fttxyokp19psoj, WALLET rail, CREDIT_POOL programme with overageBehavior=CHARGE_ORG and a 100-paise budget).
Chain: lib/payments/operations/checkout.ts ~L3263-3277 writes a WALLET PaymentLeg for the FULL nominal price whenever isOrgWalletPayment is true and debits walletBalance (10,000,000 → 9,741,674 for a 258,326-paise booking). Then lib/payments/billing/overage-settlement.ts ~L280-303 (chargeTo ORG) tries to carve the covered base out of an INVOICE_ACCRUAL leg; a WALLET org has none (carved = 0), so it falls into the additive branch its own comment calls unreachable: it creates an OVERAGE_INVOICE_ACCRUAL leg for the marginal (248,326) and increments Payment.amount to 506,652 (originalAmount 218,920 + tax 39,406 ≠ amount). The OverageEvent (PENDING) has no collection path on the WALLET rail. Cancelling within the 100% window refunds amountRefundedPaise 506,652 on the INTERNAL rail and the wallet returns to 10,000,000 — 248,326 paise richer than before the booking (Payment 68092bbd…, Refund 6ddb2f0c…, OverageEvent cmtnocd52…).
Related P1s from the same run: CHARGE_MEMBER on a WALLET-funded parent throws in overage-settlement.ts ~L225-243 (#715 gap) with no config guard and no actionable error; PROGRAM_CAP_EXHAUSTED (402) is classified as a modelled outcome for Sentry at checkout.ts ~L3748 but the rethrow at ~L3792-3810 still answers a generic 500 UNKNOWN_ERROR.
Fix (orchestrator decision): (1) on the WALLET rail an overage is already paid by the wallet debit — the ORG branch must not add a leg or touch Payment.amount; record the OverageEvent as collected-via-wallet against the WALLET leg; (2) lib/enterprise config-lock/validators refuse CHARGE_MEMBER on a WALLET-funded billing account (unimplemented, #715) with a clear error, and document CHARGE_ORG-on-WALLET as wallet-collected; (3) checkout answers PROGRAM_CAP_EXHAUSTED with its own httpStatus/code and an actionable toast; (4) one pin per change and a refund pin proving a cancelled WALLET+CHARGE_ORG booking refunds exactly the wallet debit.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MgadJydWEKkdhhzY58yiL7
Found 2026-09-05 in wave-1B E2E on the deploy preview of #1422 (union of the merged train). Reproduced on a throwaway org (LearnPro Academy cmqb27jge06fttxyokp19psoj, WALLET rail, CREDIT_POOL programme with overageBehavior=CHARGE_ORG and a 100-paise budget).
Chain: lib/payments/operations/checkout.ts ~L3263-3277 writes a WALLET PaymentLeg for the FULL nominal price whenever isOrgWalletPayment is true and debits walletBalance (10,000,000 → 9,741,674 for a 258,326-paise booking). Then lib/payments/billing/overage-settlement.ts ~L280-303 (chargeTo ORG) tries to carve the covered base out of an INVOICE_ACCRUAL leg; a WALLET org has none (carved = 0), so it falls into the additive branch its own comment calls unreachable: it creates an OVERAGE_INVOICE_ACCRUAL leg for the marginal (248,326) and increments Payment.amount to 506,652 (originalAmount 218,920 + tax 39,406 ≠ amount). The OverageEvent (PENDING) has no collection path on the WALLET rail. Cancelling within the 100% window refunds amountRefundedPaise 506,652 on the INTERNAL rail and the wallet returns to 10,000,000 — 248,326 paise richer than before the booking (Payment 68092bbd…, Refund 6ddb2f0c…, OverageEvent cmtnocd52…).
Related P1s from the same run: CHARGE_MEMBER on a WALLET-funded parent throws in overage-settlement.ts ~L225-243 (#715 gap) with no config guard and no actionable error; PROGRAM_CAP_EXHAUSTED (402) is classified as a modelled outcome for Sentry at checkout.ts ~L3748 but the rethrow at ~L3792-3810 still answers a generic 500 UNKNOWN_ERROR.
Fix (orchestrator decision): (1) on the WALLET rail an overage is already paid by the wallet debit — the ORG branch must not add a leg or touch Payment.amount; record the OverageEvent as collected-via-wallet against the WALLET leg; (2) lib/enterprise config-lock/validators refuse CHARGE_MEMBER on a WALLET-funded billing account (unimplemented, #715) with a clear error, and document CHARGE_ORG-on-WALLET as wallet-collected; (3) checkout answers PROGRAM_CAP_EXHAUSTED with its own httpStatus/code and an actionable toast; (4) one pin per change and a refund pin proving a cancelled WALLET+CHARGE_ORG booking refunds exactly the wallet debit.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MgadJydWEKkdhhzY58yiL7