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

A fortnight of turns still reads in milliseconds: the acts a read hands out are bounded #79

open not picked up yet opened this
opened this

Intent. Keep a table that has been played for two weeks as fast to open as one opened this morning, before the lapse (#77) makes long ledgers the normal case.

Measured on main today (63a4041): tableState returns every row of act for the table, every time, at every door. With 300 acts in the ledger GET /api/tables/1 is 30 KB and 14 ms, against 2 KB and 6 ms for the same table with none. A table on the shortest legal window (15 minutes) against the longest legal deadline (14 days) lapses on the order of a thousand acts a day once #77 writes them, so tens of thousands of rows is not a pathological case, it is the rules. Every live refresh refetches the page, so the page carries it again on every act.

Done looks like

  • [ ] A read hands out a bounded slice of the log — the most recent N by default, with the total count beside it and a way to ask for the ones before it (before, validated at the boundary like every other input, with its own named failure).
  • [ ] The arithmetic keeps the whole ledger. The turn is derived from the act count and the standing offer from the latest offer with the accepts after it, so what src/round.ts reads must not be what the view hands out. Do it with SQL that reads what the rules need (a count, and the acts since the latest offer) rather than by loading everything and slicing — and say in the pull which queries those are.
  • [ ] The doors follow: the page shows the latest with a way back through the older ones, the JSON answer carries the same slice and the count, and an MCP table_state answer stays small enough for a model's context.
  • [ ] A test with a thousand acts asserts the answer's size and the read's time, and asserts the turn, the standing offer and the acceptances are identical to what the unbounded read computed — a bound that changes the game is a bug, not an optimisation.
  • [ ] An index that makes it cheap (act (game_id, id) exists; say whether it is enough).

Files I expect to change. src/actions.ts, src/round.ts if the arithmetic moves, src/db.ts only if an index is missing, src/pages/tableview.ts, src/mcp.ts, src/actions.test.ts, src/server.test.ts.

Risks. This is the one change that can silently alter the rules — every acceptance the arithmetic cannot see is a binding that does not happen. Test the boundary case where the latest offer is older than the slice. It touches tableState, which #74 also touches; whichever lands second rebases.

Who. @mason, reviewed by @sentinel. Ready now.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs