Let a dealer take the table off the device it's stuck on #99

Closed
jheaps wants to merge 1 commits from feat/casino-holdem-table-file into fix/casino-holdem-touch-targets
Owner

The night lives in one browser's localStorage and nowhere else. A dealer whose phone dies, or who wants to carry on from the tablet after the break, loses the stacks, the buy-ins, where the button is and the whole hand log. The CSV export can't bring any of it back — it records what happened, not where the table stands.

What changed

The table can be written to a file and read back, from the Session panel beside the CSV export. Round-tripped through the real UI, a hand in progress comes back mid-hand: blinds posted, the same seat on the clock, the button where it was.

Loading replaces everything, so it asks first and names both sides rather than saying "are you sure":

The file has a table with 4 players in it. It was saved 9/2/2026, 1:06:12 AM. Loading it replaces the table on screen — 0 players, 0 logged hands. Undo will bring it back for a few seconds; after that it is gone.

It runs through the same undoable path as the header buttons, so the toast offers the way back — and the confirm says exactly that rather than overstating it. (My first draft of that sentence claimed it couldn't be undone, which was wrong; the measurement of the toast is what caught it.)

Reading a file goes through exactly the same migration a save from storage does: load() had that logic inline and it's now a function both call. A second, looser path for imports is how a format grows two meanings of the same field.

What it refuses, each with something a dealer can act on, and never a half-loaded table:

file says
not JSON "That file isn't a saved table — it couldn't be read as JSON."
JSON with no seats "That file doesn't have a table in it — no seats were found."
a save from another tool "That file is a save from something else, not a Hold'em table."
a newer version "That table was saved by a newer version of this tool. Update, then load it."

The last one matters: loading it would risk reading a field whose meaning has changed, and the dealer would find out from the money. What it accepts anyway: a bare table with no envelope, for somebody who copied the storage value out by hand.

Verification

13 new tests in tests/holdem/tableFile.test.js — the round trip preserving what a CSV can't carry, standings and the bank check agreeing across it, dealing straight from a loaded table, every refusal, migration of a file missing fields that exist now, and the dated filename. Suite at 400 tests, 0 failures.

Playwright MCP end to end: saved a live table mid-hand (holdem-table-2026-09-02-0106.json), wrecked it to zero players and no history, loaded the file back — names, stacks [200, 200, 339, 198], button on seat 2, table notes, bettingOpen, and the posted blinds [0, 0, 1, 2] all returned exactly. Undo put the wrecked table back. All three refusals checked with real files: correct message each time, no confirm shown, and the table byte-for-byte untouched. Layout audit clean, no console errors.

Stacked on fix/casino-holdem-touch-targets.

🤖 Generated with Claude Code

https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb

The night lives in one browser's localStorage and nowhere else. A dealer whose phone dies, or who wants to carry on from the tablet after the break, loses the stacks, the buy-ins, where the button is and the whole hand log. The CSV export can't bring any of it back — it records *what happened*, not *where the table stands*. **What changed** The table can be written to a file and read back, from the Session panel beside the CSV export. Round-tripped through the real UI, a hand in progress comes back **mid-hand**: blinds posted, the same seat on the clock, the button where it was. Loading replaces everything, so it asks first and names both sides rather than saying "are you sure": > The file has a table with 4 players in it. It was saved 9/2/2026, 1:06:12 AM. Loading it replaces the table on screen — 0 players, 0 logged hands. Undo will bring it back for a few seconds; after that it is gone. It runs through the same undoable path as the header buttons, so the toast offers the way back — and the confirm says exactly that rather than overstating it. (My first draft of that sentence claimed it couldn't be undone, which was wrong; the measurement of the toast is what caught it.) Reading a file goes through **exactly the same migration** a save from storage does: `load()` had that logic inline and it's now a function both call. A second, looser path for imports is how a format grows two meanings of the same field. **What it refuses**, each with something a dealer can act on, and never a half-loaded table: | file | says | |---|---| | not JSON | *"That file isn't a saved table — it couldn't be read as JSON."* | | JSON with no seats | *"That file doesn't have a table in it — no seats were found."* | | a save from another tool | *"That file is a save from something else, not a Hold'em table."* | | a newer version | *"That table was saved by a newer version of this tool. Update, then load it."* | The last one matters: loading it would risk reading a field whose meaning has changed, and the dealer would find out from the money. **What it accepts anyway:** a bare table with no envelope, for somebody who copied the storage value out by hand. **Verification** 13 new tests in `tests/holdem/tableFile.test.js` — the round trip preserving what a CSV can't carry, standings and the bank check agreeing across it, dealing straight from a loaded table, every refusal, migration of a file missing fields that exist now, and the dated filename. Suite at 400 tests, 0 failures. Playwright MCP end to end: saved a live table mid-hand (`holdem-table-2026-09-02-0106.json`), wrecked it to zero players and no history, loaded the file back — names, stacks `[200, 200, 339, 198]`, button on seat 2, table notes, `bettingOpen`, and the posted blinds `[0, 0, 1, 2]` all returned exactly. Undo put the wrecked table back. All three refusals checked with real files: correct message each time, no confirm shown, and the table byte-for-byte untouched. Layout audit clean, no console errors. Stacked on `fix/casino-holdem-touch-targets`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
jheaps added 1 commit 2026-09-02 01:07:43 -06:00
The night lives in one browser's localStorage and nowhere else. A dealer whose phone
dies, or who wants to carry on from the tablet after the break, loses the stacks, the
buy-ins, where the button is and the whole hand log. The CSV export can't bring any of
it back: it records what happened, not where the table stands.

The table can now be written to a file and read back. Round-tripped through the real
UI, a hand in progress comes back mid-hand — blinds posted, the same seat on the
clock, the button where it was.

Loading replaces everything, so it asks first and names both sides rather than saying
"are you sure": how many players are in the file and when it was saved, against how
many players and how many logged hands are about to go. It goes through the same
undoable path as the header buttons, so the toast offers the way back, and the
confirm says so instead of overstating it.

Reading a file goes through exactly the same migration a save from storage does —
load() had that logic inline and it is now a function both call. A second, looser path
for imports is how a format grows two meanings of the same field.

What it refuses, each with something a dealer can act on and never a half-loaded
table: anything that isn't JSON, JSON with no seats in it, a save from some other tool
that happens to carry a `kind`, and a file from a newer version — that last one
because loading it risks reading a field whose meaning has changed, and the dealer
would find out from the money. What it accepts anyway: a bare table with no envelope,
for somebody who copied the storage value out by hand.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
jheaps closed this pull request 2026-09-02 09:58:03 -06:00

Pull request closed

Please reopen this pull request to perform a merge.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jheaps/JoshHeaps.Net#99