Intent. The third of the three pieces #23 was split into, and the one a player actually feels: you leave the table open on your phone for six hours, and when you look again the page must be right rather than quietly six hours old.
Done looks like
[ ] static/live.js subscribes to the topic on the page (<body data-live-topic="table:7"> from #42) when there is one, and to everything when there is not.
[ ] Four things mean catch up, and each does exactly one refetch of the live regions, coalesced to at most one per second: the tab becoming visible again, a pageshow out of the back/forward cache, a reconnect after a drop, and a gap.
[ ] A gap is the server saying it cannot replay: when a reconnect's Last-Event-ID is older than the ring still holds, or newer than anything this process ever emitted (which is what a restart looks like from the outside), the stream sends event: gap rather than a silence the client would read as being current.
[ ] A hidden tab does no work at all — no timers, no fetches — until somebody looks at it.
[ ] The client is tested without a browser: a small hand-built document, EventSource, fetch and parser, in the style the closed branch mason/23-… used (src/live.client.test.ts), since Bun has no DOM and this app takes no dependencies. A test per trigger, and one asserting two triggers at once cause one refetch.
[ ] Still nothing polls, the heartbeat stays at 25 seconds, and the page without JavaScript is the same page, one reload behind.
Filesstatic/live.js, src/live.ts (the gap event only), src/live.client.test.ts (new), src/server.test.ts.
Risks A fake DOM is a test that can pass while the real browser drifts — keep the fake small and say in the pull what you checked by hand in a real one. Coalescing is where double-refetch bugs live: assert it, do not assume it.
Brief that fits @hearth — honest about what happens when the connection does not. (A person assigns.)
Intent. The third of the three pieces #23 was split into, and the one a player actually feels: you leave the table open on your phone for six hours, and when you look again the page must be right rather than quietly six hours old.
Done looks like
static/live.jssubscribes to the topic on the page (<body data-live-topic="table:7">from #42) when there is one, and to everything when there is not.pageshowout of the back/forward cache, a reconnect after a drop, and agap.gapis the server saying it cannot replay: when a reconnect'sLast-Event-IDis older than the ring still holds, or newer than anything this process ever emitted (which is what a restart looks like from the outside), the stream sendsevent: gaprather than a silence the client would read as being current.EventSource,fetchand parser, in the style the closed branchmason/23-…used (src/live.client.test.ts), since Bun has no DOM and this app takes no dependencies. A test per trigger, and one asserting two triggers at once cause one refetch.Files
static/live.js,src/live.ts(thegapevent only),src/live.client.test.ts(new),src/server.test.ts.Risks A fake DOM is a test that can pass while the real browser drifts — keep the fake small and say in the pull what you checked by hand in a real one. Coalescing is where double-refetch bugs live: assert it, do not assume it.
Brief that fits @hearth — honest about what happens when the connection does not. (A person assigns.)