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

The clock: turn windows, the deadline, and the impound, all derived from timestamps #11

open not picked up yet opened this
opened this

Intent. Make the game asynchronous but not stalled — a turn that goes unplayed for its window becomes a pass, and a table that reaches its deadline without an accord is impounded — with no timers, no background job, nothing but arithmetic on rows at read time.

Done looks like

  • [ ] A small src/clock.ts: given a game, its acts and a now, it says whose turn it is, when that turn lapses, how many turns have lapsed unplayed, and whether the deadline has passed. Pure, now injected, fully tested.
  • [ ] Reading or acting on a table first settles the clock: lapsed turns are written as real pass acts by the engine (seat marked, reason lapsed), and a passed deadline settles the table as impounded with every seat scored zero and everything revealed exactly as a binding accord reveals it.
  • [ ] turn_seconds (default 6h) and deadline_seconds (default 24h) are set when the table opens, validated to a sane range, and shown on the page and in the API.
  • [ ] tableState carries turn_ends_at and deadline_at as ISO strings; the page renders a countdown without layout shift, and without JavaScript still shows the absolute time.
  • [ ] Tests advance a fake clock: three windows pass and three passes appear once; the same read twice does not write twice; the deadline impounds exactly once and emit("table.impounded", …) fires once.

Files src/clock.ts (new), src/clock.test.ts (new), src/actions.ts, src/db.ts, src/page.ts, src/actions.test.ts.

Risks Lazy catch-up is idempotent or it is a bug — two readers arriving at once must not each write the pass. Do the catch-up inside one transaction with a guard on the act count.

Brief that fits @hearth — honest about what really runs, with a recoverable state. (A person assigns.)

commented

Split. RULES.md §8 is two clocks. The turn window — a window that passes unplayed becomes one pass act marked lapsed, several at once if several passed — needs only the ledger (#8, merged) and src/when.ts (#20, merged), and it is what keeps a real table moving when somebody goes quiet; it is now #77, ready.

This issue keeps the deadline and the impound, which are an ending and belong with #10 — the dependency is right and stays. #53 (a silent table still passes) sits on top of both.

commented

Note for whoever takes the deadline and the impound: #83 changes the deadline's floor from 2 × turn window to the arithmetic of a binding (quorum + 1 windows, plus slack), because on today's defaults a 5- or 6-seat table cannot bind before its deadline if the seats use their windows. Read the deadline rule from the constants after that lands, not from the numbers written here.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs