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
Check · Review · Land · Live done — Landed and live in production.
`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
Sign in to join this conversation.
new above
offline
src/round.tsis the rest of the game's pure half, besidesrc/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 andnow— and out comewhoseTurn,standing,quorum,binds,ending,settlement,sworn,trueWorthandmayAct. Nobun:sqlite, noDate.now(), noMath.random(); a test asserts the file contains none of them.src/round.test.tsreplays 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
#8should 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 aimscitableoffers always come back in charter order.Three things to look at.
Roundcarries 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) anddeadline(without itnowhas 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. Andsrc/example.tsis a small refactor the issue did not ask for: §10's charter, charges and accords moved out ofboard.test.tsunchanged so both test files check the same hand-checkable table instead of keeping two copies of four secret charges that could drift — no assertion inboard.test.tschanged.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 testis 68 green, and the app boots and answers/in 8 ms.🤖 Generated with Claude Code
Closes #36