Add replayable debug reports.
A report dumps everything needed to understand a game that went wrong:
the full state (decks card by card, shop row and tier deck order,
discards, pending choices, banked Mana/Trumpets/apples), the round's
battles, and the whole event log. Available as JSON, which replays, or
text, which reads — and the text ends with a paste-ready repro test.
Battles now record the randomness they consume alongside what they
started from, so a result can be replayed long after the round cleared
those banks: same lineups, same dice, same events, down to the log text.
Results predating the recording say so rather than quietly re-rolling.
Three ways in: the 🐛 panel's download/copy buttons, GET
/api/debug/report (DEBUG-only, since a report holds both players' hands
and the shop deck order), and `mise run report`, which reads the
database directly so a live game can be dumped without DEBUG.
This commit is contained in:
@@ -38,11 +38,49 @@ During development open the Vite URL (http://localhost:5173); it proxies
|
||||
|
||||
Set via environment or a `.env` file (see `.env.example`):
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
| ------------ | ---------- | ------------------------------------ |
|
||||
| `DATA_DIR` | `data` | Directory holding the SQLite DB |
|
||||
| `PORT` | `8080` | HTTP port |
|
||||
| `STATIC_DIR` | `web/dist` | Built frontend to serve |
|
||||
| Variable | Default | Purpose |
|
||||
| ------------ | ---------- | ------------------------------------------- |
|
||||
| `DATA_DIR` | `data` | Directory holding the SQLite DB |
|
||||
| `PORT` | `8080` | HTTP port |
|
||||
| `STATIC_DIR` | `web/dist` | Built frontend to serve |
|
||||
| `DEBUG` | off | Unlocks the in-game debug panel (see below) |
|
||||
|
||||
## Debugging a game that went wrong
|
||||
|
||||
Any saved game can be dumped as a **debug report**: the full state (every deck
|
||||
card by card, the shop row and the order of the remaining tier decks, discards,
|
||||
pending choices, each player's banked Mana/Trumpets/apples), the round's battles
|
||||
with their lineups and *the dice they rolled*, and the entire event log.
|
||||
|
||||
```sh
|
||||
mise run report # list recent games
|
||||
mise run report -- QWERT # the report, as text, for reading
|
||||
mise run report -- -json -out internal/game/testdata/bug.json QWERT
|
||||
```
|
||||
|
||||
With `DEBUG=1` the in-game 🐛 panel grows two buttons — **Download JSON** and
|
||||
**Copy as text** — that pull the same report over `GET /api/debug/report`. A
|
||||
report exposes both players' hands and the shop deck order, so that endpoint is
|
||||
DEBUG-only; on a live server use `cmd/report`, which reads the database.
|
||||
|
||||
The JSON form is the useful one, because it replays. Drop it in
|
||||
`internal/game/testdata/` and the battle re-runs exactly — same lineups, same
|
||||
dice, same events, right down to the log text:
|
||||
|
||||
```go
|
||||
rep, err := LoadDebugReportFile("testdata/bug.json")
|
||||
res, err := rep.ReplayBattle(0) // 0 = the round's first pairing
|
||||
if res.WinnerSeat != 1 { // assert what *should* have happened
|
||||
t.Fatalf("expected seat 1 to win, got %d", res.WinnerSeat)
|
||||
}
|
||||
```
|
||||
|
||||
That works because every battle records the randomness it consumed
|
||||
(`BattleResult.Draws`) alongside what it started from (`Lineups`, `Inputs`), so
|
||||
a result is replayable long after the round cleared those banks. `rep.Game()`
|
||||
hands back the whole game if the bug wasn't in the battle — carry on from the
|
||||
shop, replay a different pairing, or read a deck card by card. The text form of
|
||||
the report ends with a paste-ready version of the test above.
|
||||
|
||||
## Rules implemented
|
||||
|
||||
@@ -184,6 +222,7 @@ The Unicorn pack adds two mechanics the others don't have:
|
||||
|
||||
```
|
||||
cmd/server/ entrypoint
|
||||
cmd/report/ debug report dumper (reads the DB directly)
|
||||
internal/game/ rules engine (pure, fully tested)
|
||||
internal/ai/ computer opponent (decides from a player View only)
|
||||
internal/server/ HTTP + WebSocket rooms; drives bot turns
|
||||
|
||||
Reference in New Issue
Block a user