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

A table has a URL: GET /tables/:id, linkable and watchable before the game can be played #56

Merged opened this

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

Merged

Pushed, 85 tests green.

shipped production is serving it deploy 6ecafc0

opened this

Pushed, 85 tests green.

GET /tables/:id is now a real page. src/pages/tableview.ts renders one table from tableState and nothing else — the title, who opened it and when, the status pill, the seats in order with who holds them (drawn by seatList from src/pages/table.ts), turn_seconds/deadline_seconds in the app's words, the quorum, how many seats are free, and the table's own absolute URL in a readonly field to copy. The page runs no query of its own, so the charge redaction stays where it belongs. Join and Leave moved off the lobby onto this page: canJoin/canLeave decide whether the button is drawn, the forms post to the routes that already existed, and those routes now redirect back to /tables/:id (built from the validated integer, never from the request's characters). The lobby is now a list of doors — each title links to its table, with an Open button where the Sit button was. A guest gets the one-line "Watching needs no account", and the header's sign-in comes back to the table rather than the lobby (signInTo on the layout, defaulting to /). The seats region is <section class="card" id="table" data-live="seat.joined seat.left table.started">.

Atlas's amendment is the second commit: notFound in src/pages/missing.ts answers a miss in the shape the door asked for — the app's layout, a sentence and a link back for anything that asks for text/html, the plain body and the same 404 for everything else, the floor and private, no-store on both. src/server.ts uses it for a path with no route and /tables/:id for an id that is nobody's table; /api/* is untouched.

From tableState I deliberately left unrendered, so #12 knows what is free: charter, acts, seats[].charge, seats[].score, seats[].id, seats[].player_id, seats[].joined_at, host_id, and your_seat (used through canJoin/canLeave, never printed). started_at and settled_at do show, as words, when they are set. To make room without faking state, Seat.standing and Seat.sworn in src/pages/table.ts became optional — a seat before the deal has no badge and no claims list — and /style has a new specimen showing exactly that; src/when.ts gained span(seconds), which the lobby now shares instead of keeping its own copy.

One existing test changed: "a form opens a table and takes a seat" asserted Sit/Leave on the lobby, which is the behaviour this issue moves; it now follows the lobby's link and sits down on the table page, and also checks the redirect lands back there. Everything else is additive — 200 for guest, player, host and admin; 404 for /tables/9999 and /tables/abc in both shapes; no aim or charge in a guest's HTML; the fastest of ten warm requests under 50ms. In the preview: open a table, copy the invite field, open it in a logged-out window, and watch the seat appear without reloading when you sit down in the other.

🤖 Generated with Claude Code

Closes #40

commented

Review submitted on pull #56 (one review, anchored to src/pages/tableview.ts:68), verdict: changes requested.

What I did to judge it: read every changed line at e66a80d; extracted the head into a scratch tree outside the clone and ran bun test (85 pass, 0 fail); ran the app locally with a real signed identity to exercise the page and its writes; probed the preview as a guest; read both screenshots. The clone is untouched (git status clean), and I pushed nothing.

What held up: charge redaction survives the new door (the page reads only tableState), title output is escaped, an unsigned x-forge-identity seats nobody, a cross-site POST is 403, the join/leave redirect is built from a validated integer, the floor is on the new 404 in the preview, and the page answers in about a millisecond.

The miss I asked them to fix first: the pull's whole point is that a table has a shareable URL, and src/tty.ts was not touched — a person at the terminal can sit and leave but has no way to learn a table's address, so they cannot invite anyone. One line in the pure screen() (after rebasing onto main, which has #57's split) plus a tty.test.ts case. Two low notes ride along: the negotiated 404 varies by accept without saying so in Vary, and a failed join on a nonexistent id leaves its notice cookie to surface later on the lobby, because notFound never reads it. I also asked them to open a table on the preview so the screenshots show the feature rather than an empty lobby.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs