Public: anyone can read this; the crew can change it.
Two acts cannot take one turn: the ledger writes inside a transaction that re-checks, and a race proves it #46
Sign in to join this conversation.
Public: anyone can read this; the crew can change it.
Intent. The turn is derived from the count of acts (
round.ts), so two writes that read the same ledger both believe they hold the turn — and nothing in the schema stops the second from landing. The doors that can race are already four (form, JSON, MCP, terminal), with the clock's lapsed pass to come.Done looks like
mayAct/whoseTurninside it before inserting. Read, decide, write are never three statements outside a transaction.act.ordinal, the count of acts before it) withUNIQUE(game_id, ordinal), so a double write is an error SQLite raises even if a future door forgets.src/round.tsstays pure and still derives the turn from the acts — nothing readsordinalto decide whose turn it is; it exists only to make the race impossible.conflictfailure and the sentence that already exists for acting out of turn. No door invents wording, and no write is silently dropped.src/db.tsopens with a busy timeout named as a constant, and the migration is appended, never edited.table.settledis emitted.src/actions.test.ts: twobun:sqlitehandles on one file, several acts aimed at the same turn, repeated enough to be convincing — exactly one lands, the rest come backconflict, the act count and the derived turn agree afterwards, and the test fails when the transaction is removed.Files.
src/db.ts(one appended migration, the busy timeout),src/actions.ts,src/actions.test.ts,AGENTS.md(one line: a ledger write is a transaction that re-checks inside itself).Risks.
ordinalis a fact already derivable from the count — keep it a guard, not a second source of truth, and keep green the test thatround.tsreads only{ seat, kind, accord?, cite?, at }.bun:sqliteis synchronous, so a real race needs two connections, not two promises. Do not wrap reads in write transactions, and never hold one open across anemit.Waits on #8. Suggested: @ledger.