package game // Regression: when the economy journal is unavailable, a payout paid // through the character file must record the round's stake-resolution // evidence in that same file. Otherwise a crash before the games' own // ResolveStakes call leaves the wager records open with checkpoint // balances that no longer match, and recovery refunds chip stakes the // paid settlement had already consumed — duplicating the round's value. import ( "testing" "thehouseoficarus/internal/player" ) func TestUnjournalablePayoutCrashDoesNotRefundChips(t *testing.T) { h := newHarness(t) h.seedAccount("alice") p := h.seedCharacter("alice", "alice") h.g.RunOnOwner(func() { p.Credits = 100 p.SetInvSlot(0, &player.InventorySlot{ItemID: "chips", Quantity: 10}) w := casinoWallet{g: h.g, p: p} if _, err := w.Wager(10); err != nil { t.Error(err) return } path := h.g.Economy.path h.g.Economy.path = h.dir // persistent append failure if err := w.PayCredits(20); err != nil { t.Errorf("fallback payout failed: %v", err) return } h.g.Economy.path = path // Process loss BEFORE the game's own ResolveStakes call: the // fallback payout itself must be the durable resolution. h.g.recoverEconomy() loaded, err := h.g.AccountStore.LoadCharacter("alice") if err != nil { t.Error(err) return } if loaded.Credits != 120 || countChips(loaded) != 0 { t.Errorf("recovered credits=%d chips=%d; want 120 credits and no chips (the paid settlement consumed the stake)", loaded.Credits, countChips(loaded)) } if open := h.g.Economy.mustLoadOpen(t); len(open) != 0 { t.Errorf("records left open after recovery: %+v", open) } }) } // The stakes-open count is a proxy for "recovery did not silently refund": // with the fix the wager record settles through the file-side evidence. func TestUnjournalablePayoutEvidenceRecorded(t *testing.T) { h := newHarness(t) h.seedAccount("alice") p := h.seedCharacter("alice", "alice") h.g.RunOnOwner(func() { p.Credits = 100 w := casinoWallet{g: h.g, p: p} if _, err := w.Wager(10); err != nil { t.Error(err) return } path := h.g.Economy.path h.g.Economy.path = h.dir if err := w.PayCredits(20); err != nil { t.Errorf("fallback payout failed: %v", err) return } h.g.Economy.path = path if len(p.ResolvedStakes) == 0 { t.Error("fallback payout recorded no stake-resolution evidence; a crash before ResolveStakes would double-refund chips") } }) }