# Cash Payment / Refund Integrity Gate v35

## Why this sprint exists

Before adding automatic Payment Capture → Shift orchestration, the cumulative refund
contract needs a concurrency-safe operational projection.

v34 calculated prior refunds with an aggregate SUM over refund rows. That is correct in
single-request execution but is not a strong concurrency boundary for simultaneous refunds.

## Refund balance projection

`cash.payment_refund_balances` stores one locked refund accumulator per captured payment.

Each cash refund:

1. locks the original payment
2. locks the payment refund balance
3. validates `refunded + requested <= captured amount`
4. posts cash/shift entries
5. increments the refund projection

This makes the refundable-balance decision serializable at the payment row/projection level.

## Source of truth

`cash.sale_cash_refunds` remains the immutable historical record.

`cash.payment_refund_balances` is a rebuildable operational projection.

The migration backfills existing v34 refunds into the projection.

## Idempotency

Retrying the same refund command returns the existing refund before updating the projection,
so the balance is not incremented twice.

## Next

Only after this integrity gate is green should automatic payment-capture orchestration be
added.

A separate integrity sprint is still required for older accumulated foundation debt,
including purchasing receipt-to-invoice allocation and inventory transfer valuation.
