games: the ladder gets played, and the rack learns where to stand

Trivia had every Go test passing and had never been in a browser, which
this plan's own rule says means nothing. So: play it.

The game itself holds up. The clock drains honestly and does not restart
on a reload, the multiple compounds, walking pays exactly what the felt
quoted, the reveal marks the right answer, and the auto-submit at zero
lands as a timeout rather than an illegal move. The next question's
answer never crosses the wire.

Two bugs only the browser could show:

- The spot printed double the stake after every settled game. standing()
  set spot.amount and *then* poured the chips on, and pour grows the pile
  from what it is told is already there. The money was always right; the
  number under the chips was not, which is the one rule the felt is built
  on.

- The house rack sat on top of the multiplier at 390px. Its 5.75rem inset
  is not a margin, it is the width of blackjack's shoe — so on a phone the
  rack sits in the middle of the felt. It now shrinks on small screens and
  pulls into the corner where the corner is empty; data-at says which rack
  is which, because pulling blackjack's to the edge slides it under the
  deck.

The dev rig seeds its own question bank now (one real OpenTDB batch per
difficulty), because a fresh dev database 503s every start otherwise.
This commit is contained in:
prosolis
2026-07-14 02:33:28 -07:00
parent c62d736223
commit 2d653bf439
7 changed files with 119 additions and 29 deletions

View File

@@ -244,10 +244,9 @@ A multi-session build. This section is the handover; read it before anything els
hits the rack, nothing happens, and it looks like the bet is broken. Blackjack's
action buttons are also `[data-move="stand"]`, not `[data-stand]`.
- **Trivia, and it plays for chips.** *(2026-07-14. Built, tested, and — say it
plainly — **NOT YET DRIVEN IN A BROWSER**. Every Go test passes and `go vet` is
clean, which per this plan's own hard-won rule means nothing at all about the
table. Do that first next session; see the bottom of this entry.)*
- **Trivia, and it plays for chips.** *(2026-07-14. Built, and now **played** — see
"Driven in a browser" at the bottom of this entry, which is where the two bugs
were.)*
- **A ladder.** Stake once, then answer a run of twelve. Every right answer
multiplies what you're holding, a wrong one loses the lot, and you may walk
with what you've built. Clearing all twelve ends the run and banks it — a
@@ -284,30 +283,52 @@ A multi-session build. This section is the handover; read it before anything els
seconds, stops early when a batch adds nothing new), and a round never waits on
it. Answers are shuffled per-game against the game's own seed, so where the right
answer sits in the table tells a player nothing.
- **Left to do, and it is the whole of the risk:** `PETE_DEV_CASINO=:7788 go test
./internal/web -run TestDevCasino -timeout 0` and *play it*. Watch especially:
the bank is empty on a fresh dev database, so the first start will 503 with "the
question bank is still filling up" until the refill loop has run — the dev rig
does not start that loop, so it likely needs seeding by hand or a call to
`refillTriviaBank`. Then: does the clock bar drain honestly, does the auto-submit
at zero land as a timeout rather than a "that move isn't legal" (the GRACE window
in trivia.js is what defends this), does the reveal mark the right answer, and
does the money settle onto the shared spot the way the other three tables do.
- **The dev rig seeds its own bank.** A fresh dev database has an empty bank and
every start 503s, so `TestDevCasino` now takes one real batch per difficulty
from OpenTDB (`seedTriviaBank`) — fifty questions each, four ladders' worth,
through the same fetch-decode-store path production uses. It does *not* run
`StartTriviaBank`: a rig that spends its first two minutes dripping four hundred
questions per difficulty out of a free API is a rig you cannot use.
- **Driven in a browser, 2026-07-14, and the clock and the money hold up.** The
ladder plays: a 200 stake on Easy dealt a real OpenTDB question with its
entities decoded, the clock bar drained honestly (847px → 711px over three
seconds, countdown 18.7s → 15.7s), two right answers compounded 1.00× → 1.26×
→ 1.58×, and walking paid exactly the 311 the felt had been quoting. The
reveal marks the wrong pick red and the right answer green. A reload mid-rung
brought the board back and — the thing that matters — the server's clock kept
running through it (17.5s left before, 16.2s after; it does not restart).
**The timeout lands as a timeout**, which was the loudest worry: going quiet
through a 20s question fired the auto-submit at zero, came back 200 with a
`timeout` event and "Out of time.", not a "that move isn't legal". The next
question's answer is never sent (`correct: -1` in the ask event); only the
decided one reveals.
- **Two bugs, and only a browser could have found either.**
1. **The spot printed double the stake after every settled game.** `standing()`
set `spot.amount` and *then* poured the chips on, and `pour` grows the pile
from whatever it is told is already there — so a 200 stake settled to a spot
reading 400, and a 400 one to 800. This is exactly the rule the felt is built
on ("the number under the pile is a readout of the pile") failing quietly:
the money was always right, the *number under the chips* was not. Blackjack
and hangman pour without pre-setting; trivia now does too.
2. **The house rack sat on top of the multiplier at 390px.** The rack is a 147px
block inset 5.75rem from the edge, and that inset is not a margin — it is the
width of *blackjack's shoe*, which the rack sits beside. On a phone that puts
it in the middle of the felt, on top of trivia's "1.53×". On small screens the
rack now shrinks and, where there is nothing in the corner, pulls into the
corner. Which rack is which is what `data-at` says: unmarked is alone in the
corner, `shoe` is blackjack (pull that one to the edge and it slides under the
deck — this was caught after doing exactly that), `rail` is solitaire, whose
rack isn't on the felt at all. All four tables re-checked at 390px and 1280px,
live games on the felt: no overlap with text, no overlap with the shoe, no
horizontal overflow, desktop geometry unchanged.
### Next, in order
1. **Drive trivia in a browser** (see above) — it has never been played, and that
means nothing about it is known.
2. Phase 2's other half is now built but unproven: the question bank is
**prefetched from OpenTDB into a local table** (a per-question fetch in a web
game loop is a latency and rate-limit problem gogobee never had), through
`internal/safehttp`. It stakes chips too. The shape that fits the room is a
**ladder**: stake once, answer a run of questions, each right answer compounds
the multiple and a wrong one loses the lot, with the option to walk. Note the
real risk — trivia answers are googlable, so a tight per-question clock is the
only thing making a slow-but-correct answer worth less than a fast one. Score
the clock server-side; the browser's countdown is decoration.
2. Phase 3 (UNO), Phase 4 (hold'em) as below.
1. Phase 3 (UNO), Phase 4 (hold'em) as below.
2. Trivia is played but not deployed. Hangman, solitaire and trivia are all still
sitting on main un-deployed — the server runs `StartTriviaBank`, so its bank
fills itself once the binary is out there, but the first player to try a ladder
in the first minute after a deploy gets the 503.
Still open on the table itself, none of it blocking: **split** isn't implemented (the
engine has no move for it), the felt is roomy at desktop widths with only one seat on