Parent: #1
Depends on: #8, #9, #15
Priority: nice-to-have; not a Rendezvous v1 release gate
Outcome
Let a player leave the server browser open and see sessions appear, change capacity/status, or disappear without manually refreshing or repeatedly replacing the entire list.
Recommended transport
Use Server-Sent Events (SSE) for the first implementation because browser updates are one-way. Keep the existing bounded HTTP snapshot/query API as the source of truth and polling fallback; do not require WebSockets unless a later bidirectional feature justifies them.
Scope
Extend the browse snapshot response with a stream revision/cursor.
Add a game/environment/filter-scoped SSE endpoint using text/event-stream.
Define bounded events:
session_upsert — add or replace the public projection of one listing;
session_remove — remove a listing that expired, became stale/incompatible/full for the filter, was revoked, or changed visibility;
reset — discard local state and fetch a fresh snapshot;
keepalive comment/event for idle connections.
Give every event a monotonically ordered stream ID suitable for Last-Event-ID reconnect.
Retain only a bounded replay window. If a cursor is missing, expired, foreign, or has a sequence gap, emit/return reset rather than silently serving an incomplete view.
Add an SDK async stream API that applies events to a caller-owned local projection or returns typed deltas, cancellation, reconnect, and reset outcomes.
Coalesce heartbeat/capacity churn over a short configurable interval so the UI updates promptly without flicker or event floods.
Keep polling with jittered backoff as fallback for unsupported platforms, restrictive proxies, or repeated stream failures.
Preserve all browse filters, tenant/environment/protocol isolation, metadata limits, visibility rules, and endpoint/credential secrecy.
Document reverse-proxy buffering/timeouts and graceful shutdown/reconnect behavior.
Keep polished browser UI in each game; Rendezvous supplies contracts, SDK behavior, and TestClient diagnostics only.
Acceptance criteria
A snapshot plus subsequent events produces the same public listing projection as a fresh snapshot at the final revision.
Create, update, capacity change, UDP-presence staleness/recovery, lease expiry, deregistration, revocation, visibility change, and compatibility change produce the correct delta.
Reconnect with a retained Last-Event-ID resumes without duplicate or missing final state.
Expired/gapped/invalid cursors force a clean reset and snapshot refresh.
Cross-game, environment, protocol, visibility, and filter changes never leak through a stream.
Events expose no raw endpoints, lease credentials, capabilities, tickets, secrets, or internal store identifiers.
Slow/disconnected consumers cannot grow queues or memory without bound; they are reset or disconnected predictably.
Burst tests prove coalescing and subscriber limits bound CPU, memory, bandwidth, and event rate.
SDK cancellation/disposal closes the stream and releases all resources.
TestClient can display live add/update/remove events and deliberately exercise reconnect/reset behavior.
The UI still treats displayed capacity as advisory and join authorization revalidates current state.
Polling fallback remains supported and documented.
Parent: #1
Depends on: #8, #9, #15
Priority: nice-to-have; not a Rendezvous v1 release gate
## Outcome
Let a player leave the server browser open and see sessions appear, change capacity/status, or disappear without manually refreshing or repeatedly replacing the entire list.
## Recommended transport
Use Server-Sent Events (SSE) for the first implementation because browser updates are one-way. Keep the existing bounded HTTP snapshot/query API as the source of truth and polling fallback; do not require WebSockets unless a later bidirectional feature justifies them.
## Scope
- Extend the browse snapshot response with a stream revision/cursor.
- Add a game/environment/filter-scoped SSE endpoint using `text/event-stream`.
- Define bounded events:
- `session_upsert` — add or replace the public projection of one listing;
- `session_remove` — remove a listing that expired, became stale/incompatible/full for the filter, was revoked, or changed visibility;
- `reset` — discard local state and fetch a fresh snapshot;
- keepalive comment/event for idle connections.
- Give every event a monotonically ordered stream ID suitable for `Last-Event-ID` reconnect.
- Retain only a bounded replay window. If a cursor is missing, expired, foreign, or has a sequence gap, emit/return `reset` rather than silently serving an incomplete view.
- Add an SDK async stream API that applies events to a caller-owned local projection or returns typed deltas, cancellation, reconnect, and reset outcomes.
- Coalesce heartbeat/capacity churn over a short configurable interval so the UI updates promptly without flicker or event floods.
- Keep polling with jittered backoff as fallback for unsupported platforms, restrictive proxies, or repeated stream failures.
- Preserve all browse filters, tenant/environment/protocol isolation, metadata limits, visibility rules, and endpoint/credential secrecy.
- Bound subscribers, per-tenant streams, replay memory, queued events, connection duration, keepalive frequency, and slow-consumer behavior.
- Document reverse-proxy buffering/timeouts and graceful shutdown/reconnect behavior.
- Keep polished browser UI in each game; Rendezvous supplies contracts, SDK behavior, and TestClient diagnostics only.
## Acceptance criteria
- A snapshot plus subsequent events produces the same public listing projection as a fresh snapshot at the final revision.
- Create, update, capacity change, UDP-presence staleness/recovery, lease expiry, deregistration, revocation, visibility change, and compatibility change produce the correct delta.
- Reconnect with a retained `Last-Event-ID` resumes without duplicate or missing final state.
- Expired/gapped/invalid cursors force a clean reset and snapshot refresh.
- Cross-game, environment, protocol, visibility, and filter changes never leak through a stream.
- Events expose no raw endpoints, lease credentials, capabilities, tickets, secrets, or internal store identifiers.
- Slow/disconnected consumers cannot grow queues or memory without bound; they are reset or disconnected predictably.
- Burst tests prove coalescing and subscriber limits bound CPU, memory, bandwidth, and event rate.
- SDK cancellation/disposal closes the stream and releases all resources.
- TestClient can display live add/update/remove events and deliberately exercise reconnect/reset behavior.
- The UI still treats displayed capacity as advisory and join authorization revalidates current state.
- Polling fallback remains supported and documented.
Started on codex/issue-26-sse-browser-updates from the verified #23 checkpoint. I will preserve the bounded snapshot API as source of truth, add scoped/bounded SSE replay and reset semantics, expose typed SDK/TestClient behavior, and verify isolation, churn coalescing, slow-consumer bounds, cancellation/disposal, and polling fallback before reconciling the issue.
Started on `codex/issue-26-sse-browser-updates` from the verified #23 checkpoint. I will preserve the bounded snapshot API as source of truth, add scoped/bounded SSE replay and reset semantics, expose typed SDK/TestClient behavior, and verify isolation, churn coalescing, slow-consumer bounds, cancellation/disposal, and polling fallback before reconciling the issue.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Parent: #1
Depends on: #8, #9, #15
Priority: nice-to-have; not a Rendezvous v1 release gate
Outcome
Let a player leave the server browser open and see sessions appear, change capacity/status, or disappear without manually refreshing or repeatedly replacing the entire list.
Recommended transport
Use Server-Sent Events (SSE) for the first implementation because browser updates are one-way. Keep the existing bounded HTTP snapshot/query API as the source of truth and polling fallback; do not require WebSockets unless a later bidirectional feature justifies them.
Scope
text/event-stream.session_upsert— add or replace the public projection of one listing;session_remove— remove a listing that expired, became stale/incompatible/full for the filter, was revoked, or changed visibility;reset— discard local state and fetch a fresh snapshot;Last-Event-IDreconnect.resetrather than silently serving an incomplete view.Acceptance criteria
Last-Event-IDresumes without duplicate or missing final state.Started on
codex/issue-26-sse-browser-updatesfrom the verified #23 checkpoint. I will preserve the bounded snapshot API as source of truth, add scoped/bounded SSE replay and reset semantics, expose typed SDK/TestClient behavior, and verify isolation, churn coalescing, slow-consumer bounds, cancellation/disposal, and polling fallback before reconciling the issue.Implemented and verified on
codex/issue-26-sse-browser-updates.Commit:
06c4ecf feat(browser): stream bounded live session updates (#26)Delivered:
session_upsert,session_remove,reset, andkeepaliveevents;watchdiagnostics plus deliberate--exercise-reconnectand--exercise-resetflows;Verification:
codex/issue-26-sse-browser-updatesto codex/issue-26-sse-browser-updates