docs(web-ui/shape): fix stale CSS bundle count, SSE route prefix, bind-retry cap claims

Verified against frontend/packages/dashboard/build.mjs, hive-c0re/src/dashboard/mod.rs,
and hive-agent/src/web_ui/mod.rs:
- dashboard ships 9 page CSS bundles + colors/theme/common, not 4
- dashboard SSE routes are /api/dashboard/stream + /api/dashboard/history, not
  /dashboard/stream + /dashboard/history
- per-agent bind_with_retry has a MAX_BIND_ATTEMPTS=12 cap (gives up), unlike the
  dashboard's genuinely uncapped retry loop
- assets/swarm.js, assets/call.js -> swarm.js, call.js (no assets/ dir exists)
This commit is contained in:
iris 2026-08-15 12:22:52 +02:00 committed by mara
commit 26b55f34d3

View file

@ -16,10 +16,14 @@
- `GET /static/*` → bundled CSS + JS produced by esbuild
(`frontend/packages/{dashboard,agent}/build.mjs`). Both pages
pull the shared terminal pane + Catppuccin palette + typography
from `@hive/shared` (was `hive-fr0nt`); the dashboard ships four
CSS bundles (`common.css` loaded by every page, plus per-page
`dashboard.css` / `flow.css` / `logs.css`); `common.css` inlines
`base.css` + `terminal.css` via esbuild's `@import` resolution.
from `@hive/shared` (was `hive-fr0nt`); the dashboard ships one
CSS bundle per page (`colors.css` + `theme.css` + `common.css`,
loaded by every page, plus a page-specific bundle —
`dashboard.css` / `flow.css` / `logs.css` / `home.css` /
`settings.css` / `stats.css` / `core.css` / `builds.css` /
`credentials.css`); `common.css` inlines `@hive/shared`'s
`base.css` + `terminal.css` + `tabs.css` + `chrome.css` +
`pill.css` via esbuild's `@import` resolution.
`terminal.js` exports `{ create, linkify }` as ES module
members; a back-compat shim in the IIFE bodies still exposes
a `window.HiveTerminal` global for callers that need it. The dashboard's
@ -42,14 +46,14 @@
high-water mark at the moment the snapshot was assembled);
clients use it to dedupe their buffered SSE traffic against
the snapshot (drop frames with `seq <= snapshot.seq`).
- `GET /dashboard/stream` (dashboard) / `GET /events/stream`
- `GET /api/dashboard/stream` (dashboard) / `GET /events/stream`
(per-agent) → `text/event-stream` SSE for live updates. The
dashboard stream carries broker `Sent` / `Delivered` (mirrored
by a forwarder task from the broker's intra-process channel)
plus mutation events (`approval_added` / `approval_resolved`,
`question_added` / `question_resolved`, `transient_set` /
`transient_cleared`). Each frame carries a `seq`. The
matching backfill endpoint is `GET /dashboard/history` (last
matching backfill endpoint is `GET /api/dashboard/history` (last
~200 broker messages wrapped in `{ seq, events }`) on the
dashboard and `GET /events/history` (last 2000 `LiveEvent`s
also wrapped in `{ seq, events }`) on the agent.
@ -201,7 +205,7 @@ re-render), call `refreshState()`. State shapes live in
`hive-c0re/src/dashboard/state_snapshot.rs::StateSnapshot` and
`web_ui/state.rs::StateSnapshot` — when
adding state fields, plumb through the snapshot struct and the
relevant domain module (`assets/swarm.js`, `assets/call.js`, etc.) render function.
relevant domain module (`swarm.js`, `call.js`, etc.) render function.
**Focus preservation:** `refreshState` checks whether
`document.activeElement` sits inside one of the managed sections
@ -277,18 +281,20 @@ previews are type-aware:
Both bind their TCP listener with `SO_REUSEADDR` via
`tokio::net::TcpSocket` plus a retry loop on `AddrInUse`
(exponential backoff capped at 2s, **no attempt cap**) so an nspawn
restart that races the previous process's socket release resolves
itself. The retry is uncapped on purpose: a capped budget once
left the harness silently UI-less for the rest of its lifetime
when a back-to-back restart held the port longer than the cap
allowed. Genuine port collisions are preflighted host-side
(`lifecycle::{spawn,rebuild}` refuses with a clear error,
surfaced on the dashboard as a banner), so at this layer a
persistent `AddrInUse` always reflects a recoverable stale
socket — retrying forever is the safe choice. The first 12
attempts log at WARN; after that the level drops to INFO so a
long-held stale socket doesn't flood the journal.
(exponential backoff capped at 2s) so an nspawn restart that races
the previous process's socket release resolves itself, but the two
binaries differ on the attempt budget. The dashboard's
`bind_with_retry` (`hive-c0re/src/dashboard/mod.rs`) has **no
attempt cap** — retrying forever is deliberate, since genuine port
collisions are preflighted host-side (`lifecycle::{spawn,rebuild}`
refuses with a clear error, surfaced on the dashboard as a banner),
so at this layer a persistent `AddrInUse` always reflects a
recoverable stale socket. Its first 12 attempts log at WARN; after
that the level drops to INFO so a long-held stale socket doesn't
flood the journal. The per-agent UI's `bind_with_retry`
(`hive-agent/src/web_ui/mod.rs`) instead gives up after
`MAX_BIND_ATTEMPTS` (12) and returns the `AddrInUse` error rather
than looping forever.
The per-agent UI optionally binds a `UnixListener` instead of
TCP when `HIVE_WEB_SOCKET` is set — the unix-socket transition