Hashed seat tokens, ledgered inputs, refusable moves, disk-checked codes, host-only bots, and a drift script

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141G6xqLeNRYEtviLWSB5Up
This commit is contained in:
Eric Wagoner
2026-09-23 12:07:53 -04:00
co-authored by Claude Fable 5.1
parent ddb18cb08a
commit c934bbe434
12 changed files with 173 additions and 47 deletions
+12 -5
View File
@@ -25,9 +25,13 @@ README.
ledger line, so it replays with the game, and the hall counts lines said
while you were away.
- **The ledger** is the append-only JSONL file that *is* the game: room,
seats, start (seed and rules revision), turns (inputs only), talk, over.
A room is its ledger replayed through a deterministic engine; nothing else
is saved. Ledgers survive deploys and restarts and are backed up nightly.
seats, start (seed and rules revision), each seat's submitted input, the
turn that resolves them, talk, over. A room is its ledger replayed
through a deterministic engine; nothing else is saved. A half-written
round survives a restart because every input is written as it arrives.
Ledgers survive deploys and restarts and are backed up nightly, so they
hold nothing secret: a seat line carries the SHA-256 of its token, never
the token, which goes once to the browser that earned it.
- **Report** in the masthead opens the slip: what happened, what you
expected, a screenshot if you have one. It is pinned to the room and the
round. **The keeper** replies; the reply appears under the report in the
@@ -68,8 +72,11 @@ a sandboxed systemd service, behind Caddy `handle` blocks that route `/api`
and `/ws` before the static files. Rooms in memory are evicted after a week
idle and come back from disk on the next visit. Rate limits sit on the doors
a stranger can knock on (rooms, seats, talk, the desk); a table of friends
never nears them. Seat tokens never leave the server except to the browser
that earned them; a shared link carries none.
never nears them. A seat token is minted once, sent once, and compared by
hash in constant time ever after; a shared link carries none. Room codes
are checked against the disk as well as memory, so an evicted room's code
is never reissued over its ledger. A game may refuse a move with a reason
(`validate`), and the player sees the reason.
## Operations