2026-08-07 13:08:56 +02:00
|
|
|
---
|
|
|
|
|
id: CB-WP-0031
|
|
|
|
|
kind: product
|
|
|
|
|
title: "The comment box outlives the game"
|
|
|
|
|
status: done
|
2026-08-07 16:09:36 +02:00
|
|
|
state_hub_workstream_id: "7b7450cd-3972-4c78-a53c-fba54b3fc02b"
|
2026-08-07 13:08:56 +02:00
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# Purpose
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
structural tier S (one channel reopened on an existing page; no new
|
|
|
|
|
decision, no new dependency, no budget moved)
|
|
|
|
|
chaos d8 = 2 → no override
|
|
|
|
|
declared tier S
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Declaration 2 of chaos window 3**, opened 2026-08-07 by ADR-0017.
|
|
|
|
|
|
|
|
|
|
## The report
|
|
|
|
|
|
|
|
|
|
> *"Before we move on, i want to be able to add comments after the game
|
|
|
|
|
> finished."*
|
|
|
|
|
|
|
|
|
|
## What was actually broken, and it was two things
|
|
|
|
|
|
|
|
|
|
**The channel closed at the moment it is worth most.** A player who has
|
|
|
|
|
just seen the outcome is the one with something to say — *"so that is why
|
|
|
|
|
that failed"*, *"I never understood what that card did"* — and that is the
|
|
|
|
|
reading the whole trial protocol (GameDesign §5) exists to collect. It was
|
|
|
|
|
collectable at every moment of the game **except** the one after it.
|
|
|
|
|
|
|
|
|
|
Two independent defects, either of which alone shuts the channel:
|
|
|
|
|
|
|
|
|
|
| where | what |
|
|
|
|
|
|---|---|
|
|
|
|
|
| `doc::ending` | never rendered the comment box at all |
|
|
|
|
|
| `hotseat::serve_end` | had no `POST /note` arm — a hand-built post fell through to `404 the game is over` |
|
|
|
|
|
|
|
|
|
|
**Fixing either alone leaves it shut**, which is why the test asserts both
|
|
|
|
|
and why a markup-only test would have passed against a server that still
|
|
|
|
|
refused.
|
|
|
|
|
|
|
|
|
|
## The thing that needed deciding: what a post-game note is bound to
|
|
|
|
|
|
|
|
|
|
A note is bound to a position by `state_hash` (ADR-0014 D3), and the
|
|
|
|
|
position is genuinely the final state. But **`round` and `step` say *when
|
|
|
|
|
the player said it***, and a note written after the outcome is on screen
|
|
|
|
|
is not an observation made at the last decision point.
|
|
|
|
|
|
|
|
|
|
`RoundStep` has an `End` variant — **the last step of a round, not the end
|
|
|
|
|
of the game.** Logging a post-game note under it would file an
|
|
|
|
|
after-the-fact reading as an in-play one: a value that is correct about the
|
|
|
|
|
wrong subject, which is the family ADR-0018 was written for two hours
|
|
|
|
|
earlier.
|
|
|
|
|
|
|
|
|
|
So `record_note` takes the step **as an argument** rather than reading it
|
|
|
|
|
off the state, and the post-game path passes `"after the end"` — which
|
|
|
|
|
cannot collide with a `Debug` identifier.
|
|
|
|
|
|
|
|
|
|
## No box where there is nothing to bind to
|
|
|
|
|
|
|
|
|
|
A game that stopped without a result has no final position. The box is
|
|
|
|
|
**not offered** there, and the page says why. Offering one that would
|
|
|
|
|
answer `409` is a control that exists to be hit.
|
|
|
|
|
|
|
|
|
|
## Task: reopen the channel
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: CB-WP-0031-T01
|
|
|
|
|
status: done
|
|
|
|
|
priority: high
|
2026-08-07 16:09:36 +02:00
|
|
|
state_hub_task_id: "6b92d470-b3a2-4cde-a307-d20cb6a45ab4"
|
2026-08-07 13:08:56 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Controls:**
|
|
|
|
|
- **the test fails on each half separately** — mutation-proven: blanking
|
|
|
|
|
the form gives *"the ending page offered no comment box"*, removing the
|
|
|
|
|
server arm gives `404`; both green when restored;
|
|
|
|
|
- **a note must not end the session** — every other POST in `serve_end`
|
|
|
|
|
breaks the loop, and a player must be able to write a second note and
|
|
|
|
|
then still press `play again`. The test posts a command after the note
|
|
|
|
|
and requires it to still work;
|
|
|
|
|
- **the redirect carries the token**, which is the defect that twice made
|
|
|
|
|
a *saved* note read as a failed one;
|
|
|
|
|
- **the log distinguishes when it was written** from the position it binds
|
|
|
|
|
to.
|
|
|
|
|
|
|
|
|
|
**Done 2026-08-07.**
|
|
|
|
|
|
|
|
|
|
`note_form` extracted and shared by both pages — a hand-written twin is
|
|
|
|
|
how one of them quietly stops posting anywhere useful. The placeholder
|
|
|
|
|
differs, and only that: what a player has to say mid-turn and what they
|
|
|
|
|
have to say having seen the result are not the same prompt.
|
|
|
|
|
|
|
|
|
|
**A test-harness defect worth recording.** The first draft wrote
|
|
|
|
|
`Content-Length: 21` beside a 22-byte body; the server read 21 bytes and
|
|
|
|
|
answered `400 unrecognised field`, which looked exactly like the feature
|
|
|
|
|
being broken. The fix was to derive the length from the body in the shared
|
|
|
|
|
`post` helper — **a hand-written length is a second copy of a fact the
|
|
|
|
|
body already carries**, the same shape as the 62 untagged literals
|
|
|
|
|
`facts-check` counts.
|
|
|
|
|
|
|
|
|
|
## Not done here
|
|
|
|
|
|
|
|
|
|
- **Notes are still not shown back to the player.** Neither page echoes
|
|
|
|
|
what has been written; the trial log is the only place they exist. That
|
|
|
|
|
is a real gap and it is not this report.
|