Skip to content

Dashboard: one realtime socket, revision-based invalidation - #402

Merged
smb merged 16 commits into
mainfrom
feat/issue-387
Oct 10, 2026
Merged

smb merged 16 commits into
mainfrom
feat/issue-387

Conversation

@smb

@smb smb commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

One realtime socket per channel and durable, revision-based panel invalidation for every write (epic #389).

  • ✨ Features:
    • Per-channel, per-resource revision counters (migration 0047) bumped by one committed-resource notifier that every write path uses: API routes, Durable Object alarms, chat commands, EventSub handlers, maintenance and retention jobs, compensation and failure branches, cross-channel fan-out
    • Dependency map declares which dashboard resources a write affects
    • Panels compare the revision vector on connect, on every hint and on window focus and invalidate exactly the advanced queries; lost hints self-heal
    • Guard test fails when a mutating route or alarm handler bypasses the notifier
  • 🚀 Performance:
    • The shell owns exactly one WebSocket per channel; navigation no longer opens or closes sockets
    • No interval polling while connected; polling only as fallback while offline; per-key throttling of refreshes
  • 🐛 Defects (found in review):
    • Reconcile on every transition to connected; socket closes and reconnects are cancelled on auth loss or sign-out
    • Module settings saves refresh related panel queries; overlay editor starts only from fresh data
    • BELABOX failures and oversized chat voting closes reach the panel; hints carry no data or secrets
  • 🧪 Tests: two-client regressions per area, committed-failure paths, lost-hint self-heal, channel isolation, no secret fields; changed e2e specs repeat-each=10

Closes #387

smb added 16 commits October 10, 2026 13:14
- Realtime data layer
  - Keep one shell-owned WebSocket per channel across same-channel navigation.
  - Centralize realtime query invalidation and reconcile channel data after reconnect.
- Polling and worker relays
  - Disable connected-state polling for chat voting, votekick, ads, and BELABOX while preserving offline fallback.
  - Relay chat_voting, belabox, and votekick live-state hints to panel sockets.
  - Refresh chat voting when a shared votekick ballot opens or closes.
- #387 regression coverage
  - Cover socket reuse, query invalidation, fallback polling, worker relays, shared-ballot invalidation, frozen event snapshots, and overlay selection safety.
  - Preserve module query ordering and stable layouts.
Realtime query refresh
- Throttle active query keys to one leading and one trailing read per second.
- Reconcile channel queries on every socket connection and keep fallback polling active only offline.

Regression coverage
- Cover saved chat-voting defaults, cached first-connect reconciliation, and sustained fast hints.
- Preserve event snapshots and editor drafts through refreshes; references #387.
Realtime refresh behavior

- Avoid settings refreshes for module event hints while bounding repeated query refreshes.
- Keep chat-voting defaults current after settings writes on a connected socket.

Regression coverage

- Cover sustained realtime hints and one-socket navigation across dashboard views for #387.
- Realtime lifecycle
  - Gate the channel socket on authentication, channel selection, and sign-out state.
  - Dispose disabled sockets immediately and cancel pending reconnect timers.
- Overlay editor
  - Initialize from fresh overlay and variable data while module state loads independently.
  - Keep the fixed loading frame until module state resolves.
- Regression coverage
  - Verify 401 reconnect cancellation and guarded logout with a dirty editor draft.
  - Cover continuous variable updates during a pending module read. (#387)
- Realtime protocol (#387)
  - Add panel-only bounded `{ part }` hints with strict payload validation and throttled query invalidation.
  - Keep module overlay payloads on overlay sockets.
- Module state transitions
  - Relay chat voting, BELABOX, and votekick changes after commits, including BELABOX failures and terminal ballot transitions.
  - Publish hints independently of overlay payload size limits.
- Regression coverage
  - Cover relay routing, secret-free hints, failure transitions, and oversized chat voting closes.
  - Verify single-socket navigation across 10 repeated e2e runs.
- #387 Durable revisions: add per-resource D1 triggers and Durable Object counters with bounded, data-free panel hints.

- #387 Notifier coverage: fan out committed writes from channel, module, auth, EventSub, platform, alarm, and maintenance paths.

- #387 Dashboard: share one channel socket, reconcile revisions on hints, connect, and focus, and poll only while offline.

- #387 Regressions: cover query mapping, channel isolation, failure commits, secret-free hints, fallback polling, and navigation without socket churn.
- Chat voting realtime coverage (#387)
  - Guard routes, chat commands, alarms, ballot writes, and word approvals with committed-resource invalidation.
  - Keep connected panel refreshes driven by server-confirmed state with polling disabled.
- Test compatibility (#387)
  - Align fixtures and saved-duration coverage with the chat voting kind model and 0046/0047 schema.
- #387 Add commit-coupled resource revisions, per-channel outbox delivery, and write dependency coverage across D1 and Durable Object commits.
- #387 Reconcile query revisions on socket connect, hints, and focus; keep refresh polling as an offline fallback.
- #387 Recheck panel authorization at send and handshake time, and await socket closure after membership or session revocation.
- #387 Add route and alarm registry guards, migration and lost-hint regressions, two-client coverage, and repeated navigation E2E checks.
- Authorization: #387 version queued revocations and recheck socket membership and sessions before close.
- Delivery: #387 retry failed socket closures and reconcile every affected committed channel.
- Coverage: #387 guard runtime alarm handlers and add regressions for cross-client freshness and route dependencies.
Issue #387

- Publish all queued channel revisions after authenticated channel commits, with unauthenticated fanout guarded.

- Retry revision reads and affected query refreshes with capped backoff; cancel pending retries on socket disposal and auth renewal.

- Preserve per-key trailing refresh ordering and cover cross-channel delivery, retry recovery, and teardown.
- #387: claim pending channel revisions with recoverable leases and bounded delivery concurrency
- #387: drain cross-channel commits while keeping local Durable Object reconciliation direct
- #387: recheck socket capacity at acceptance and cover fan-out, lease recovery, and concurrent handshakes
- Schema: place the lease migration after main’s 0050 and update the health sentinel.
- Regression guard: reject duplicate migration numbers.
- #387: preserve migration ordering for bounded revision delivery.
Implements #387.

- Drain races
  - Reconcile local DO commits while D1 leases are active.
  - Keep newer D1 revisions queued with compare-and-delete cleanup.
- Background commits
  - Share an outer-finally drain across waitUntil tasks and DO alarms.
- Regression coverage
  - Exercise both lease interleavings and stream readback failure after commit.
  - Guard the source registry against unwrapped waitUntil paths.
- Mark local delivery successful only after revision reads and reconciliation complete.
- Recover local DO revisions after a claimed delivery fails.
- Add the D1/DO interleaving regression test (Refs #387).
- Keep panel GETs read-only across core and module routes.
- Back off failed BELABOX samples and add an explicit manager schedule refresh.
- Cover GET revision invariants and bounded realtime requests for #387.
- Runtime
  - Add passive ballot snapshot and availability RPCs for panel reads.
- Regression coverage (#387)
  - Exercise registered panel GETs against expired chat-voting and votekick ballots; assert unchanged D1/DO revision vectors and zero hints.
@sonarqubecloud

Copy link
Copy Markdown

@smb
smb merged commit ba4d9a1 into main Oct 10, 2026
7 checks passed
@smb
smb deleted the feat/issue-387 branch October 10, 2026 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Data layer: single socket and realtime invalidation

1 participant