[#100] Clear the loan shelf between games (Closes #100) #102

Merged
robertismo merged 1 commit from 100-shelf-reset into master 2026-09-30 10:53:40 +00:00
Owner

What shipped

openLoanOffers is the phase-scratch global behind (market-loans). PR #101 fixed the cross-game leak by nilling it at run() start, which covers turn-1 HOOK reads. But the bench path loads brain files in assignPlayers BEFORE run(), and defvar initializers are evaluated AT LOAD: a brain that caches the shelf at load, e.g. (defvar pool-est (length (market-loans))), still captured the previous game's leftover shelf and carried it as cached state for the whole game.

This PR moves the authoritative clear to the construction boundary: NewGame now nils the shelf the moment a new game is created, before any brain file parses. run()'s clear stays as a second guard.

Why not gate (market-loans) outside the loan phase

The dispatch suggested that as defense in depth. I left it out on purpose: within a running game the shelf doubles as last turn's loan book, and deposit-phase reads of it are the same information regime as the #84 deposit/bond snapshots (last-turn book). Gating the accessor would change what brains observe mid-game and shift bench economics. The construction-boundary clear fully closes the cross-game leak without touching in-game semantics.

Regression test

TestNewGameClearsShelfBeforeBrainLoad mirrors the bench path: it plants a stale shelf (a previous game's leftovers), calls NewGame, loads a probe brain whose defvar shelf-at-load (length (market-loans)) runs AT LOAD, posts that value on turn 1, and asserts it is 0. It also verifies the hook really fired (a runs counter read back via the env) and that the shelf was rebuilt by the first loan phase, so it cannot pass vacuously.

Red/green: the test fails on master as of this branch's base (turn-1 post 0.5000 = the capped nonzero stale read) and passes with the NewGame clear.

Gates

  • go build OK
  • go test -count=1 . OK (includes #101's TestGameStartClearsStaleShelf)
  • go vet ./... OK

Diff: game.go + shelf_load_test.go only.

## What shipped `openLoanOffers` is the phase-scratch global behind `(market-loans)`. PR #101 fixed the cross-game leak by nilling it at `run()` start, which covers turn-1 HOOK reads. But the bench path loads brain files in `assignPlayers` BEFORE `run()`, and `defvar` initializers are evaluated AT LOAD: a brain that caches the shelf at load, e.g. `(defvar pool-est (length (market-loans)))`, still captured the previous game's leftover shelf and carried it as cached state for the whole game. This PR moves the authoritative clear to the construction boundary: `NewGame` now nils the shelf the moment a new game is created, before any brain file parses. `run()`'s clear stays as a second guard. ## Why not gate `(market-loans)` outside the loan phase The dispatch suggested that as defense in depth. I left it out on purpose: within a running game the shelf doubles as last turn's loan book, and deposit-phase reads of it are the same information regime as the #84 deposit/bond snapshots (last-turn book). Gating the accessor would change what brains observe mid-game and shift bench economics. The construction-boundary clear fully closes the cross-game leak without touching in-game semantics. ## Regression test `TestNewGameClearsShelfBeforeBrainLoad` mirrors the bench path: it plants a stale shelf (a previous game's leftovers), calls `NewGame`, loads a probe brain whose `defvar shelf-at-load (length (market-loans))` runs AT LOAD, posts that value on turn 1, and asserts it is 0. It also verifies the hook really fired (a `runs` counter read back via the env) and that the shelf was rebuilt by the first loan phase, so it cannot pass vacuously. Red/green: the test fails on master as of this branch's base (turn-1 post 0.5000 = the capped nonzero stale read) and passes with the `NewGame` clear. ## Gates - `go build` OK - `go test -count=1 .` OK (includes #101's `TestGameStartClearsStaleShelf`) - `go vet ./...` OK Diff: `game.go` + `shelf_load_test.go` only.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Winnie/bankwars!102
No description provided.