aboutsummaryrefslogtreecommitdiff
path: root/building_guide/concurrency.md
diff options
context:
space:
mode:
Diffstat (limited to 'building_guide/concurrency.md')
-rw-r--r--building_guide/concurrency.md56
1 files changed, 38 insertions, 18 deletions
diff --git a/building_guide/concurrency.md b/building_guide/concurrency.md
index 1a61670..ff8c049 100644
--- a/building_guide/concurrency.md
+++ b/building_guide/concurrency.md
@@ -19,6 +19,11 @@ Rules:
block the caller until the closure has executed on the owner. Connection
goroutines submit one task per input line, giving per-client backpressure
without ever blocking another client.
+- A FULL task queue applies backpressure: submitters block until the owner
+ drains a task, and a full queue never bypasses the owner — running a task
+ on the caller's goroutine while the owner keeps executing would break the
+ single-owner invariant. Only a STOPPED owner (graceful shutdown, after
+ admissions have closed) lets stragglers execute inline.
- Code already running on the owner must NOT call `Game.RunOnOwner` — it
would deadlock waiting for itself. Owner-executed code calls functions
directly.
@@ -43,29 +48,44 @@ synthetic tests but production Games always have the owner (started by
Every wager and payout is journaled before the balance mutation
(`internal/game/economy.go`, `data/economy/journal.jsonl`):
-1. A durable journal record with balance checkpoints (before/after) is
- appended and fsynced.
+1. A durable journal record with balance checkpoints (before/after credits
+ and chips) is appended and fsynced.
2. The in-memory balance mutates.
3. The character save makes the balance durable.
-4. A settlement marker closes the record.
+
+Two record kinds exist:
+
+- **wager** — a committed stake. The record stays OPEN while the stake is
+ outstanding (round in flight) and is resolved when the round settles:
+ won, lost, pushed, forfeited (disconnect), or refunded (shutdown). Games
+ resolve stakes through `casino.Wallet.ResolveStakes` after settlement;
+ `casino.Wallet.RefundOutstanding` returns every outstanding stake
+ (chips as chips, credits durably) at shutdown/eviction, exactly once.
+- **payout** — money movement (winnings, pushes, refunds). The record
+ closes when the balance mutation is durable.
A failed save reverts the in-memory mutation and voids the record — the
game must not proceed on a stake that could not be made durable, and the
-player is told the house could not process the transaction (distinct from an
-insufficient-funds message). Payouts keep their record open when the save
-fails; startup recovery re-pays the owed settlement.
-
-At startup (`game.New`), open records are reduced (latest line per record ID
-wins) and compensated:
-
-- open **wager** with the file at the pre-debit balance → void (nothing was
- charged);
-- open **wager** with the file at the post-debit balance → the stake is
- **refunded** (the round state was lost in the crash);
-- open **payout** with the file at the pre-payout balance → the payout is
- **re-applied** (the player is owed it);
-- otherwise the record settles, or is surfaced for operator inspection when
- the balance is ambiguous.
+player is told the house could not process the transaction (distinct from
+an insufficient-funds message). A failed payout keeps its record open (the
+reported win is never announced as paid) and startup recovery re-pays the
+owed settlement.
+
+At startup (`game.New`), open records are compensated in two phases:
+
+1. Open **payout** records (append order, evolving balance): file at the
+ pre-payout balance → re-apply (the player is owed it); at the post-payout
+ balance → already durable, settle; anything else stays open and is
+ surfaced for operator inspection — a liability is never silently
+ dropped.
+2. Open **wager** records (newest first, so each refund restores the
+ balance the previous record's checkpoints refer to): file at the
+ pre-debit state (credits AND chips) → void (nothing was charged); at
+ the post-debit state → the stake is **refunded** (the round state was
+ lost in the crash) — unless a later payout record proves the round
+ resolved (the win/push/refund already returned the stake inside that
+ payout), in which case only the lost resolution marker is re-applied.
+ Ambiguous records stay open for operator inspection.
Currency arithmetic is checked (`internal/casino/credits.go`): explicit
`MaxCredits` cap, bounded `DefaultMaxBet` default (the explicit unlimited