mirror of
https://github.com/hanzoai/commerce.git
synced 2026-10-30 15:08:42 +00:00
Red's re-review of the credit code, fixed. credit() read the row, then took the payer's hold, then marked the credit in a swap that only asked "is it credited". A reconciler on another replica (or the same one, on the next tick) could fail the payment in between: fail() released the hold, saw Credited false so reversed nothing, and closed the row for good. The request's swap then set Credited on that failed row and landed it — real money in the payer's balance for a payment Gateway refused, on a row no pass reads again, so nothing ever took it back. The swap now refuses a row that is Failed, and the pass that finds it not owed hands back the room it took and lands nothing. The Deferred flag is refused on a failed row too, so its view cannot promise a credit that will not come. TestACreditNeverLandsOnAFailedRow reproduces it: with the guard removed the row ends Failed+Credited+Landed with 700 cents posted; with it, the row stays failed, the ledger sees nothing and the hold is empty.