Fixes the money bug flagged earlier. When an instance died mid-round its players had already been debited, so their stakes sat with the house: balanced books, quietly robbed players. Every instance now sweeps for unresolved rounds and refunds them. Such a round is marked void, not settled. The schema caught this: the reveal_is_complete constraint requires a settled round to publish its seed, and an abandoned round has no outcome to reveal. Void is a distinct state with its own column and a check that the two are exclusive. Claiming happens before money moves, so concurrent reconcilers on different instances refund exactly once. Adds TestFullPlayerJourney: sign-in with no account, fund, scratch, bet with an auto target, settle, verify the round independently, check the ledger history is continuous, transfer to a friend, and confirm the books still sum to zero. It asserts against the ledger rather than the API's own summary. Adds cmd/loadtest. One instance on 4 cores held 25,000 concurrent websocket connections with zero failures at 586MB RSS, about 26KB per connection, with the load generator competing for the same CPU. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
22 lines
934 B
SQL
22 lines
934 B
SQL
-- A round that is abandoned is not the same as a round that settled.
|
|
--
|
|
-- Settlement means an outcome was produced, which is why reveal_is_complete
|
|
-- requires a settled round to publish its seed. A round whose instance died
|
|
-- mid-flight has no outcome at all: there is nothing to reveal, and marking it
|
|
-- settled would either violate that constraint or, worse, publish a seed for a
|
|
-- round that never resolved.
|
|
--
|
|
-- Voiding is its own state: stakes are returned and the round is closed with no
|
|
-- result.
|
|
|
|
ALTER TABLE rounds ADD COLUMN voided_at TIMESTAMPTZ;
|
|
|
|
COMMENT ON COLUMN rounds.voided_at IS
|
|
'Set when a round was abandoned and its stakes refunded. Mutually exclusive with settled_at.';
|
|
|
|
ALTER TABLE rounds ADD CONSTRAINT round_not_both_settled_and_void
|
|
CHECK (settled_at IS NULL OR voided_at IS NULL);
|
|
|
|
CREATE INDEX rounds_unresolved_idx ON rounds (opened_at)
|
|
WHERE settled_at IS NULL AND voided_at IS NULL;
|