aboutsummaryrefslogtreecommitdiff
path: root/building_guide
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-09-16 19:57:45 -0400
committerhistoria <[not public]>2026-09-16 19:57:45 -0400
commit6ef40a5739f1723ec26cc32dfc48fe764f776dca (patch)
treee215a4dc96ea639bcea07bb589aae3e31c3609bb /building_guide
parent1dad15698845d370e998f7cc5feb8aece3fab58f (diff)
downloadthehouseoficarus-6ef40a5739f1723ec26cc32dfc48fe764f776dca.tar.gz
fix: durable payouts survive journal failure, cap bank withdrawals, hash passwords off the owner loop.
Diffstat (limited to 'building_guide')
-rw-r--r--building_guide/concurrency.md36
1 files changed, 35 insertions, 1 deletions
diff --git a/building_guide/concurrency.md b/building_guide/concurrency.md
index 984a61d..2fa4558 100644
--- a/building_guide/concurrency.md
+++ b/building_guide/concurrency.md
@@ -37,6 +37,17 @@ Rules:
per-message write deadlines. A full queue disconnects only that client.
- Saves run on the owner and serialize a value snapshot; concurrent
read-modify-write cycles of the same files cannot happen.
+- Password work is the one deliberate exception: Argon2id verification and
+ hashing (~64 MiB, tens of milliseconds) run on the CALLER's connection
+ goroutine in `HandleSessionOnOwner` (`StatePassword` and
+ `StateNewAccount` are intercepted before any owner task is submitted).
+ A burst of logins therefore costs memory and CPU on connection
+ goroutines, never a stall of the owner's command/tick queue. The owner
+ task re-checks the stored hash against the one that was verified so a
+ password change mid-login cannot authorize a stale attempt, and
+ `player.hashLimiter` caps concurrent Argon2id computations at 4.
+ All resulting state transitions (echo, session state, account saves)
+ still happen on the owner.
Unit tests construct Games without an owner; such Games run submitted tasks
inline on the caller's goroutine (legacy behavior), which is fine for
@@ -126,6 +137,26 @@ 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.
+If the JOURNAL ITSELF cannot be appended (persistent write failure, e.g. a
+deleted or unwritable `data/economy`), appends are retried and then the
+wallet degrades safely:
+
+- A **wager** is never charged without a journal record — the bet is
+ rejected with the persistence message (unchanged).
+- A **payout** falls back to paying through the character file alone (the
+ save is the commit point), so the settlement is real, announced, and
+ durable even with no journal record. `ResolveStakes` then records the
+ unresolved stake IDs in the character file (`player.Player
+ .ResolvedStakes`) as durable resolution evidence, and recovery settles
+ those stakes without refunding them (no double pay, and a settlement's
+ chip stake is not returned in kind on top of credits that already
+ returned it). If the character save fails too, no evidence exists and
+ the open wager record drives the ordinary refund-on-lost-state recovery.
+- A journal that cannot be fully READ (oversized or unreadable line)
+ aborts recovery and compaction entirely: records are preserved verbatim
+ for operator inspection instead of compensating over a partial fold or
+ truncating the file.
+
At startup (`game.New`), open records are compensated in two phases:
1. Open **payout** records (append order, evolving balance): file at the
@@ -145,7 +176,10 @@ At startup (`game.New`), open records are compensated in two phases:
Currency arithmetic is checked (`internal/casino/credits.go`): explicit
`MaxCredits` cap, bounded `DefaultMaxBet` default (the explicit unlimited
sentinel is still honored), floor conversion for payout multipliers, and
-overflow rejected instead of wrapping.
+overflow rejected instead of wrapping. The cap is shared by the wallet:
+bank withdrawals are rejected when they would push the on-hand balance
+past it, and gameplay credit grants (shop sales, pickups, activity
+payouts) clamp at the cap and log rather than wrap.
## Account lifecycle transactions