Skip to content

feat: enforce approved rewards have a payment at the database#1679

Open
JoeriDijkstra wants to merge 2 commits into
developfrom
feat/fund-reward-approved-requires-payment-check
Open

feat: enforce approved rewards have a payment at the database#1679
JoeriDijkstra wants to merge 2 commits into
developfrom
feat/fund-reward-approved-requires-payment-check

Conversation

@JoeriDijkstra

Copy link
Copy Markdown
Contributor

Add a CHECK constraint on fund_rewards (status <> 'approved' OR payment_id IS NOT NULL) so the invariant can't be broken by a future non-Multi path. Currently it is only guaranteed by the approval Multi in app code.

The constraint is evaluated per-statement and Postgres cannot defer CHECKs, so the approval Multi had to stop transiently leaving a reward :approved with a null payment_id: create the payment bookkeeping entry first, then a single compare-and-swap sets status and payment_id together. The CAS still serializes concurrent approvals — a losing writer updates 0 rows and rolls its payment back with the transaction.

The migration adds the constraint NOT VALID then VALIDATEs it separately, so the deploy never holds an exclusive lock across the validation scan.

Addresses the "approved rewards must have payment_id" tech-debt ticket (nonblocker from PR #1503 review).

jdijkstra-eyra and others added 2 commits July 23, 2026 10:47
Add a CHECK constraint on fund_rewards (status <> 'approved' OR payment_id
IS NOT NULL) so the invariant can't be broken by a future non-Multi path.
Currently it is only guaranteed by the approval Multi in app code.

The constraint is evaluated per-statement and Postgres cannot defer CHECKs,
so the approval Multi had to stop transiently leaving a reward :approved with
a null payment_id: create the payment bookkeeping entry first, then a single
compare-and-swap sets status and payment_id together. The CAS still serializes
concurrent approvals — a losing writer updates 0 rows and rolls its payment
back with the transaction.

The migration adds the constraint NOT VALID then VALIDATEs it separately, so
the deploy never holds an exclusive lock across the validation scan.

Addresses the "approved rewards must have payment_id" tech-debt ticket
(nonblocker from PR #1503 review).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0179xMCWA3jhqdCpg6r28Y6g
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