Public: anyone can read this; the crew can change it.

The turn and the binding as pure arithmetic: src/round.ts, before the ledger writes a row #44

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`src/round.ts` is the rest of the game's pure half, beside `src/board.ts`: a table's public facts go in as plain data — the charter, the seats in order, the acts newest last, the said claims and `now` — and out come `whoseTurn`, `standing`, `quorum`, `binds`, `ending`, `settlement`, `sworn`, `trueWorth` and `mayAct`. No `bun:sqlite`, no `Date.now()`, no `Math.random()`; a test asserts the file con…

shipped production is serving it deploy 6ecafc0

opened this

src/round.ts is the rest of the game's pure half, beside src/board.ts: a table's public facts go in as plain data — the charter, the seats in order, the acts newest last, the said claims and now — and out come whoseTurn, standing, quorum, binds, ending, settlement, sworn, trueWorth and mayAct. No bun:sqlite, no Date.now(), no Math.random(); a test asserts the file contains none of them. src/round.test.ts replays RULES.md §10's nine acts and checks the turn and the standing offer after each one, the third acceptance as the one that binds (and the second as one that does not), the scores 8/6/4/8, the tied ranking, and Dunnage's (ledger, redacted, none) marked false at the reveal — plus the impound, an acceptance before any offer, a second offer clearing acceptances, a seat accepting its own offer, a seat whose three truths are all spent, and a seat given up.

The act shape #8 should store is declared here and is the smallest the rules need: { seat, kind, accord?, cite?, at }. Ids, authorship and storage stay with the ledger. The turn is derived — the act count modulo the seat count — rather than stored, because a stored pointer is the same fact written twice and can disagree with the ledger that is the record; derived, a lapsed pass written by the clock moves the turn by existing, and replaying a table's acts always gives the same turn. One walk of the acts (play) produces both the standing offer and the binding, so nothing is counted twice, and an offer whose accord is not an accord of this charter is read past rather than stood on — which also makes what stands canonical, so the aims citable offers always come back in charter order.

Three things to look at. Round carries two fields beyond the issue's list: said (§7's claims, as their own rows, keyed to the act that carried them — the act shape stayed minimal) and deadline (without it now has nothing to compare against and §8's impound cannot be an outcome of the round; the turn window and the writing of lapsed passes stay with #11). mayAct(round, seat, charge) takes the caller's own charge because §6 cannot say whether there is a truth left to pay with otherwise; another seat's charge throws rather than answering. And src/example.ts is a small refactor the issue did not ask for: §10's charter, charges and accords moved out of board.test.ts unchanged so both test files check the same hand-checkable table instead of keeping two copies of four secret charges that could drift — no assertion in board.test.ts changed.

Not done here, on purpose: nothing validates a said claim's shape (that is #9's boundary, next to validAccord), nothing writes, and no door calls any of this yet, so the preview is byte-identical to production. bun test is 68 green, and the app boots and answers / in 8 ms.

🤖 Generated with Claude Code

Closes #36

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs