Public: anyone can read this; the crew can change it.
A table you can open and sit at: schema, seats and state, replacing the notes demo #7
commented
Amended by the planner. startTable moves to #8 with the rest of the turn engine, so this issue does not need src/board.ts: it ends with a table that can be opened, joined, left and read, still in status open. Everything else in the body stands, minus the startTable bullet and its seed/deal wording.
Sign in to join this conversation.
Intent. Replace the template's notes with the game's own state — tables, seats and a redacted view of a table — so the app's actions, API, page, MCP tools and terminal all speak about tables from here on.
Done looks like
src/db.ts(never editing one that ran):game(id, title, statusopen|playing|settled|impounded, host_id, host_name, seed, seats_max 4–6, quorum, turn_seconds, deadline_seconds, created_at, started_at, settled_at),seat(id, game_id, player_id, player_name, ordinal, charge_json, score, joined_at) withUNIQUE(game_id, player_id)andUNIQUE(game_id, ordinal), andact(id, game_id, seat_id, kind, accord_json, at) ready for the turn engine.src/actions.ts, each(db, who, input)in and data or a named failure out:listTables,openTable(a signed-in person only; title validated 1–60 chars; seats_max 4–6),joinTable(a seat is a forge identity; no second seat at the same table; refused once playing or full),leaveTable(only before the table starts),startTable(host or admin, 4+ seated, deals fromsrc/board.tswith a seed stored on the game, fixes seat order, sets the deadline), andtableState.tableStateredacts by viewer, and tests prove it: a guest and a non-seated user see the charter, seats, status and act log but no charge; a seated player sees their own charge and nobody else's; after settlement everyone sees everything.GET /lists tables,GET /api/tablesandGET /api/tables/:idanswer, the MCP tools andsrc/tty.tsstill call real actions, and the app boots with/under 50ms.emit("table.opened" | "seat.joined" | "table.started", …)and the page region carries the matchingdata-live.src/actions.test.tscover every refusal by name: anon opening, joining twice, joining a full or started table, starting with three seats, starting as a non-host.Files
src/db.ts,src/actions.ts,src/actions.test.ts,src/routes.ts,src/page.ts,src/mcp.ts,src/tty.ts,src/server.test.ts,README.md.Risks This is the run where the demo goes away — keep every door compiling and
bun testgreen in the same commit. Charges are secret state in a column: the redaction belongs in the action, not in the page, or the next door leaks it.Brief that fits @ledger — state changes as rows with a reason, and authorization written first. (A person assigns.)