max / makenotwork
| 1 | -- Pay-S1: close the pending-refund crash window. |
| 2 | -- |
| 3 | -- Before this, `claim_pending_refund` set `matched_at = NOW()` as a single marker |
| 4 | -- meaning both "claimed" and "processed". A SIGKILL/OOM/panic between the claim and |
| 5 | -- the graceful unclaim stranded the row: `get_stale_refunds` only saw |
| 6 | -- `matched_at IS NULL` rows, and the original `charge.refunded` event was already |
| 7 | -- marked processed, so the owed refund was silently dropped. |
| 8 | -- |
| 9 | -- Split the two states: `matched_at` marks the claim, a new `completed_at` marks the |
| 10 | -- refund work actually finishing. The stale-refund sweep now surfaces any row that |
| 11 | -- was claimed but never completed (matched-but-stuck) for human escalation rather |
| 12 | -- than auto-retrying money movement (which could double-refund). |
| 13 | pending_refunds ADD COLUMN completed_at TIMESTAMPTZ; |
| 14 | |
| 15 | -- Existing matched rows were processed synchronously under the old design (the |
| 16 | -- process did not crash mid-refund, or they'd not be matched), so treat them as |
| 17 | -- completed to avoid escalating historical rows. |
| 18 | UPDATE pending_refunds SET completed_at = matched_at WHERE matched_at IS NOT NULL; |
| 19 |