diff --git a/frontend/packages/dashboard/src/builds.js b/frontend/packages/dashboard/src/builds.js index 3d719914..1e8daa96 100644 --- a/frontend/packages/dashboard/src/builds.js +++ b/frontend/packages/dashboard/src/builds.js @@ -794,7 +794,14 @@ async function init() { await refreshState(); - const es = openStream('/api/dashboard/stream'); + // kinds= matches SSE_HANDLERS below verbatim — narrows this from all + // 17 wire kinds down to the 3 this page acts on. This page was one + // of 4 unfiltered `/api/dashboard/stream` subscribers before this + // (subscription discipline, part 1 of the dashboard-event-stream- + // split issue). + const es = openStream( + '/api/dashboard/stream?kinds=rebuild_queue_changed,meta_inputs_changed,meta_update_running', + ); if (es) { es.onmessage = (e) => { let ev; diff --git a/frontend/packages/dashboard/src/core.js b/frontend/packages/dashboard/src/core.js index 7a4c467d..3a454aca 100644 --- a/frontend/packages/dashboard/src/core.js +++ b/frontend/packages/dashboard/src/core.js @@ -509,7 +509,15 @@ async function init() { await refreshState(); - const es = openStream('/api/dashboard/stream'); + // kinds= matches SSE_HANDLERS below verbatim — narrows this from all + // 17 wire kinds down to the 4 this page acts on. This page was one + // of 4 unfiltered `/api/dashboard/stream` subscribers before this + // (subscription discipline, part 1 of the dashboard-event-stream- + // split issue). + const es = openStream( + '/api/dashboard/stream?kinds=tombstones_changed,container_state_changed,' + + 'capabilities_changed,tool_groups_changed', + ); if (es) { es.onmessage = (e) => { let ev; diff --git a/frontend/packages/dashboard/src/logs.js b/frontend/packages/dashboard/src/logs.js index 3d377b30..81e081ad 100644 --- a/frontend/packages/dashboard/src/logs.js +++ b/frontend/packages/dashboard/src/logs.js @@ -384,8 +384,12 @@ import '@hive/shared/hive-tab-strip.js'; loadContainerLists(); // Subscribe to the dashboard SSE stream for audit live-appends. + // kinds= narrows this from all 17 wire kinds down to the 1 this page + // acts on. This page was one of 4 unfiltered `/api/dashboard/stream` + // subscribers before this (subscription discipline, part 1 of the + // dashboard-event-stream-split issue). { - const es = openStream('/api/dashboard/stream'); + const es = openStream('/api/dashboard/stream?kinds=audit_entry_added'); if (es) { es.onmessage = (e) => { let ev; diff --git a/frontend/packages/dashboard/src/tabs.js b/frontend/packages/dashboard/src/tabs.js index 9b2af49c..ab079b78 100644 --- a/frontend/packages/dashboard/src/tabs.js +++ b/frontend/packages/dashboard/src/tabs.js @@ -314,12 +314,25 @@ window.marked = marked; tool_groups_changed: applyToolGroupsChanged, }; (function bindDashboardStream() { - // Route through the SharedWorker so all open hyperhive tabs share - // one upstream SSE connection — see docs/web-ui.md (SSE multiplexing - // paragraph) for the design + Firefox throttling motivation. - // `openStream` returns an EventSource-shaped facade with a graceful - // direct-EventSource fallback when SharedWorker isn't supported. - const es = openStream('/api/dashboard/stream'); + // Route through the SharedWorker so all open hyperhive tabs on the + // SAME kinds= filter share one upstream SSE connection — see + // docs/web-ui/shape.md (SSE multiplexing paragraph) for the design + // + Firefox throttling motivation. `openStream` returns an + // EventSource-shaped facade with a graceful direct-EventSource + // fallback when SharedWorker isn't supported. + // + // kinds= matches MUTATION_HANDLERS below verbatim, plus `sent` + // (checked separately, just above, for the operator inbox) — + // narrows this from all 17 wire kinds down to the 13 this page + // actually acts on. This page was one of 4 unfiltered + // `/api/dashboard/stream` subscribers before this (subscription + // discipline, part 1 of the dashboard-event-stream-split issue). + const es = openStream( + '/api/dashboard/stream?kinds=sent,approval_added,approval_resolved,' + + 'question_added,question_resolved,transient_set,transient_cleared,' + + 'container_state_changed,container_removed,rebuild_queue_changed,' + + 'schedules_changed,capabilities_changed,tool_groups_changed', + ); es.onmessage = (e) => { let ev; try { ev = JSON.parse(e.data); } catch { return; }