Declare CB-WP-0018: the browser is a client, tier M
Provenance: the maintainer reported 'after some time i get an empty page back. I guess the game crashes or ends but that is unclear as the ui disappears.' Reproduced by driving a real game to completion over HTTP: move 5 accepted, then GET / -> Connection refused. The game ENDED normally, 5 rounds and 30 commands, and its whole result -- coalitions, scores, winners, hash -- went to the terminal. next_choice only accepts connections inside a human decision point, so when play() returns the listener dies and the post-ok reload is refused. A crash and a win render identically: nothing. Same class as CB-WP-0016's silent drop. Also carries the chaos rate change CB-EV-0015 owed to the next declaration (d4 -> d8, second window of 12), which is what makes this structurally M. Rolled at the old d4=3, no override, because a rate changes when the decision lands and not retroactively. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
332d8f1bba
commit
e8bb7263f2
1 changed files with 173 additions and 0 deletions
173
workplans/CB-WP-0018-the-browser-is-a-client.md
Normal file
173
workplans/CB-WP-0018-the-browser-is-a-client.md
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
---
|
||||
id: CB-WP-0018
|
||||
kind: product
|
||||
title: "The browser is a client: game over, a log, and where a drop goes"
|
||||
status: todo
|
||||
---
|
||||
|
||||
# Purpose
|
||||
|
||||
```
|
||||
structural tier M (changes how the loop constrains its own operation:
|
||||
the chaos rate d4 → d8 and a second calibration
|
||||
window, owed by CB-EV-0015 §5)
|
||||
chaos d4 = 3 → no override
|
||||
declared tier M
|
||||
```
|
||||
|
||||
**Declaration 1 of the second chaos window** — opened by T04 below, at the
|
||||
rate T04 sets. This declaration was rolled at the old d4, because the rate
|
||||
changes when the decision lands, not retroactively.
|
||||
|
||||
## The defect: a finished game is indistinguishable from a crash
|
||||
|
||||
Reported: *"after some time i get an empty page back. I guess the game
|
||||
crashes or ends but that is unclear as the ui disappears."*
|
||||
|
||||
Reproduced by driving a real game to completion over HTTP:
|
||||
|
||||
```
|
||||
move 5 accepted → ok
|
||||
GET / → URLError: [Errno 111] Connection refused
|
||||
```
|
||||
|
||||
The game **ended normally** — 5 rounds, 30 commands — and everything it
|
||||
produced went to the terminal:
|
||||
|
||||
```
|
||||
coalition [P2] score 0
|
||||
coalition [P3] score 0
|
||||
winners
|
||||
game over — 30 commands, hash f6c890a65271
|
||||
```
|
||||
|
||||
The browser got nothing, because `next_choice` only accepts connections
|
||||
*inside* a human decision point. When `play()` returns, `run_game` writes
|
||||
the outcome to stdout and the process exits; the listener dies and the
|
||||
page's post-`ok` reload is refused.
|
||||
|
||||
**The browser is a second-class client.** Every terminal outcome — the
|
||||
result, the scores, the winners, and every error `run_game` can return —
|
||||
is invisible to the only interface a player is actually using. A crash and
|
||||
a win render identically: nothing.
|
||||
|
||||
This is the same defect class as CB-WP-0016's silent drop. The system
|
||||
refuses to say what happened and the player is left to infer it.
|
||||
|
||||
## Task: serve the end of the game
|
||||
|
||||
```task
|
||||
id: CB-WP-0018-T01
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
When `play()` returns — **`Ok` or `Err`** — the browser must be told, on
|
||||
the page, in terms a player understands.
|
||||
|
||||
- **A win** shows the outcome the spectator projection already carries:
|
||||
totals, threshold, coalitions, mastery, winners.
|
||||
- **An error** shows that the game ended badly and why. `run_game`
|
||||
currently returns `Err(String)` to a terminal nobody is reading.
|
||||
- The final page must **not** auto-reload into a refused connection.
|
||||
|
||||
The listener has to outlive the game, which it does not today. Decide how
|
||||
it ends — a timeout, an explicit close, or serving until interrupted — and
|
||||
say why; a server that never exits is its own defect.
|
||||
|
||||
**Controls:** a test that plays a game to its end through the socket and
|
||||
asserts the final GET returns a page naming the outcome, **not** a refused
|
||||
connection. And the error path, driven by a game that fails, asserting the
|
||||
reason reaches the page.
|
||||
|
||||
## Task: a game log, and what to do next
|
||||
|
||||
```task
|
||||
id: CB-WP-0018-T02
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Requested: *"a game log about the events that have been generated and a
|
||||
hint of what the next move/options are."*
|
||||
|
||||
The events exist — `validate` produces them and `record::to_scenario`
|
||||
already turns them into a scenario file. The page shows none of them, so a
|
||||
player sees state change with no account of why.
|
||||
|
||||
- **The log** is the event stream, in the recorder's vocabulary. Do not
|
||||
invent a fourth phrasing: `cb-play`'s `describe()` exists precisely so
|
||||
*"what the player reads is what the scenario file will say"*, and the
|
||||
HTML renderer currently uses `{c:?}` Debug instead. Reuse it or say why
|
||||
it cannot be reused.
|
||||
- **The hint** is what the seat may do now, which is `legal` — already in
|
||||
hand, already rendered as cards by CB-WP-0017. The hint is the *step*
|
||||
context that makes those cards make sense: what the round is waiting
|
||||
for, and what happens when it stops waiting.
|
||||
|
||||
**Control:** the log must be derived from the events the aggregate
|
||||
produced, not re-narrated from the state. A log that describes the state
|
||||
after the fact is a second implementation of the rules and will drift.
|
||||
|
||||
## Task: say where a drop goes, and what it means
|
||||
|
||||
```task
|
||||
id: CB-WP-0018-T03
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Requested: *"an overlay arrow pointing to the droptarget element with an
|
||||
explanation showing up besides it, when we drag on it."*
|
||||
|
||||
CB-WP-0017 marks every legal target. What it does not do is say what any
|
||||
particular drop **means** — the player sees five outlined boxes and must
|
||||
still guess which one does what.
|
||||
|
||||
So the explanation is the substance and the arrow is the delivery. Both
|
||||
need the meaning to exist as data first, and **ADR-0010 Decision 1 binds
|
||||
here**: the description of what `action-attack → seat-1` does must be
|
||||
written by Rust into the page. The script may render it on hover; it may
|
||||
not compose it.
|
||||
|
||||
**Controls:** every advertised target carries a description, and the
|
||||
description a target shows is the one Rust wrote for *that* pair — a
|
||||
mutation that shows a neighbouring pair's text must go red. The set
|
||||
equality property from ADR-0010 D2 must still hold.
|
||||
|
||||
## Task: close the chaos change, and the evidence
|
||||
|
||||
```task
|
||||
id: CB-WP-0018-T04
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
CB-EV-0015 §5 recommended and did not make the change, on the grounds that
|
||||
it alters how the loop constrains its own operation and was therefore owed
|
||||
a tier-M declaration. This is it.
|
||||
|
||||
**Make it or reject it**, in `specs/InnerLoop.md` and `gates.toml`:
|
||||
|
||||
- rate **d4 → d8**;
|
||||
- a **second window of 12** declarations;
|
||||
- new retirement condition: *retire if an override changes nothing twice
|
||||
running*.
|
||||
|
||||
The argument to test rather than assume: both overrides were informative
|
||||
*because they were rare*. If that is right the rate should fall; if the
|
||||
real driver was that they landed on passes with something to find, the
|
||||
rate is irrelevant and the recommendation is wrong. Say which, and note
|
||||
that n=2 is thin evidence for a rate change — including the possibility
|
||||
that the honest answer is to keep d4 for another window and decide with
|
||||
four data points instead of two.
|
||||
|
||||
Then `evidence/CB-EV-0016-*.md`:
|
||||
|
||||
- **What the maintainer's three reports have cost and bought**, now that
|
||||
there are three in a row and every one found something no test did.
|
||||
- **Whether stage 1 closes.**
|
||||
- **Quote CB-WP-0017's cost by re-running the instrument**, not from
|
||||
memory — CB-EV-0015 §6 found that quoting a remembered figure defeats
|
||||
the rule even when the boundary is right, and this is the first pass
|
||||
that can apply that correction.
|
||||
Loading…
Add table
Add a link
Reference in a new issue