CB-WP-0018-T02: a game log the player can read

bot::Journal -- a shared list of Applied { actor, command, events } the
driver appends to via play_journaled; play delegates with None so
nothing existing changed. BotGame.events only appears after play
returns, which is no use to a page rendered mid-game.

Phrased with record::to_step, the recorder's vocabulary, so what the
player reads is what the scenario file will say, and all 29 GroundEvent
variants now render in words instead of Debug.

A command that produced no events says 'no effect'; the mutation
dropping that branch goes red. Honest limitation recorded: the reported
SOLVE case is resolved inside the system's resolve command, which does
produce events for other seats, so it shows as a selection with no claim
following rather than an explicit 'no effect'. Making it explicit would
mean the renderer deciding why a rule did nothing -- a second
implementation of the rules, which this task's control forbids.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-03 02:15:30 +02:00
parent 57639623da
commit 7a78c58404
6 changed files with 333 additions and 15 deletions

View file

@ -165,7 +165,7 @@ against a face-down problem, or against a suit the seat cannot match?**
```task
id: CB-WP-0018-T02
status: todo
status: done
priority: high
```
@ -196,6 +196,41 @@ for them and reproduce the silence. So the log must distinguish *"this
command produced these events"* from *"this command produced none"*
the second is the one the player needs and the harder one to render.
**Done 2026-08-03.** `bot::Journal` — a shared list of `Applied { actor,
command, events }` the driver appends to, via the new `play_journaled`.
`play` delegates to it with `None`, so nothing existing changed. The
journal exists because `BotGame.events` only appears *after* `play`
returns, which is no use to a page rendered mid-game.
The log is phrased with `record::to_step` — the recorder's vocabulary, so
what the player reads is what the scenario file will say — and every one
of the 29 `GroundEvent` variants now renders in words rather than `{:?}`.
From a live game:
```
P1 select_action action=INVESTIGATE problem=2
→ P1 chose Investigate on problem 2
the round resolve
→ problem 2 turned face up
→ P1 drew a solution
→ step → Resolve
the round end_round
→ round 2 ended; P2 leads next
```
**A command that produced no events says `no effect`**, which is the whole
point; the mutation that drops that branch goes red.
**An honest limitation.** The reported case — SOLVE doing nothing — is
*not* rendered as `no effect`, because the SOLVE is resolved inside the
system's `resolve` command, which does produce events for other seats. The
player now sees the selection and sees no claim follow it, which is a
large improvement on silence but is still an inference. Making it explicit
would mean the renderer deciding *why* a rule did nothing, which is a
second implementation of the rules — exactly what this task's control
forbids. Left as an inference deliberately, and owed to `ground-game` as
the question of whether the move should be offered at all.
## Task: say where a drop goes, and what it means
```task