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

The clock ticks when nobody is looking: a silent table still passes, still impounds, still tells the next seat #53

open not picked up yet opened this
opened this

Intent. #11 settles the clock at read time, which is the right arithmetic and the wrong end of the day: four seats go quiet overnight, nobody opens the page, and the table neither passes a lapsed turn nor impounds at its deadline until somebody happens to look — so "it is your move" (#16) never fires for the seat whose turn it became.

Done looks like

  • [ ] One in-process ticker started by serve() — never a second process, never a cron, never a timer per table. A named constant (say 60 seconds) says how often.
  • [ ] A tick asks one indexed question — the playing tables whose turn window or deadline is already past — and calls exactly the settle function #11 exposes. It decides no rule of its own: a rule that exists both in the ticker and in src/clock.ts is the bug this issue is trying not to create.
  • [ ] A tick with nothing to do writes nothing, logs nothing and costs one query; say what it measured with 100 tables open.
  • [ ] Idempotent against a concurrent reader: a tick and a read of the same table cannot write the same lapsed pass twice, guarded by #46's re-checking transaction, with a test that runs both against one database file.
  • [ ] Every write a tick makes emits what the same write emits when a player causes it — act.made, turn.changed, table.impounded — so an open page and a waiting agent learn without a reload, and the payload stays an address (#23).
  • [ ] The ticker stops when the server stops (#31): no timer keeps the process alive, and a test asserts the handle is cleared.
  • [ ] Tests drive an injected clock, never a real wait: four seats go silent for three turn windows with nobody reading the table — the three passes appear exactly once, the deadline impounds exactly once, every seat scores zero, and a fresh process reads the same settled table.

Files src/server.ts, src/clock.ts (from #11), src/actions.ts, src/server.test.ts, a line in AGENTS.md saying where a timer may live and why there is only one.

Risks A background job is the one thing #11 deliberately refused, so this has to earn it by being tiny: one interval, no state, no rules, and cheap when idle — every preview runs one too. If the sweep can be made lazier still (only tables whose next deadline is inside the next tick), do that and say so. Land it after #46, or the race it closes is the race it opens.

Who @mason to build; @sentinel to read the write path, since this is the one writer with no person behind it.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs