dashboard: trim comment bloat in tabs.js + swarm.js

Per mara's guidance on hyperhive#3901 (target ~15% comment density
overall, less where obvious, more where not; prefer docs for
abstract/general topics; don't restate facts in multiple places;
don't document history).

tabs.js: removed 4 pure "X now lives in Y" / "moved to Z" historical
asides (the underlying facts are already documented in
docs/web-ui/dashboard.md, not lost by removing the floating in-code
aside) and merged one comment block that had drifted into restating
the same fact twice (one ticker feeding two live displays, documented
as if it were two separate tickers).

swarm.js: cut a comment narrating the removal history of two features
that no longer exist in the code (a per-agent queued-badge and a
client-side jobq tally), keeping only the design constraint still in
force (why the jobq-derived state here is deliberately narrow); cut a
comment documenting a removed CSS class's history down to a statement
of the current class's purpose; cut a comment restating the
jobq-rollup rendering rationale already stated once, above, down to a
one-line pointer; trimmed a "legacy flat layout is bit-identical"
history clause down to what the depth-0 case actually renders.
This commit is contained in:
iris 2026-09-02 01:32:47 +02:00
commit 08f4f60106
2 changed files with 17 additions and 54 deletions

View file

@ -56,27 +56,16 @@ const selectionState = new Set();
// ─── job queue rollup (queue-summary banner only) ────────────────────────── // ─── job queue rollup (queue-summary banner only) ──────────────────────────
// //
// The ONE piece of job-queue-derived state on this page, and deliberately // The ONE piece of job-queue-derived state on this page, and deliberately
// narrow — mara, on review of the DagView migration: "swarm.js should not // narrow — mara: "swarm.js should not need to pull in the jobq to do its
// need to pull in the jobq to do its job." An earlier version of this file // job." Rendering is owned by the shared `JobqRollup` Preact component
// fetched GET /api/jobq/graph (the full node tree) for two things: a // (same one swarm-ui's /jobs page mounts, self-fetching
// per-agent queued-but-not-running badge (`queuedOpsByAgent()`, removed // GET /api/jobq/rollup); this file just calls `render(h(...))` and bumps
// per "remove the per agent pending stuff - only show what is running" — // a refresh token to force a refetch.
// a card's pending badges are transients-only now, which already means
// "what is running") and this banner, which was pulled entirely per "dont
// replace one legacy thing with another" (a client-side tally over the
// generic graph was itself judged a stopgap). Rendering itself later
// moved out to the shared `JobqRollup` Preact component (same one
// swarm-ui's /jobs page mounts), which owns its own fetch of
// GET /api/jobq/rollup — this file just calls Preact's own
// `render(h(...))` directly (no `mountX()` wrapper: `render` is
// already the re-render/diff entry point, per mara on review) and
// bumps a refresh token to force a refetch.
// //
// Rendered into #jobq-rollup-section, a sibling of #containers-section // Rendered into #jobq-rollup-section, a sibling of #containers-section
// kept OUTSIDE that section's per-render `replaceChildren()` wipe (see // kept OUTSIDE that section's per-render `replaceChildren()` wipe (see
// dashboard.html's comment on the mount div) — rendering into a // dashboard.html) — a section that gets wiped on every container-state
// section that gets wiped on every container-state tick would defeat // tick would defeat the component owning its own fetch lifecycle.
// the component owning its own fetch lifecycle.
let jobqRollupToken = 0; let jobqRollupToken = 0;
export function initJobqRollup() { export function initJobqRollup() {
@ -334,12 +323,9 @@ function buildContainerLi(c, node, opts) {
pending, opRunning, selected, pending, opRunning, selected,
url, containerBase, forgeBase, s, url, containerBase, forgeBase, s,
} = opts; } = opts;
// A single `pending-running` class now covers the whole "has at // A single `pending-running` class covers any active transient
// least one badge" state — there's no more queued-but-not-running // badge state (see the pending-badge derivation comment in
// row to distinguish it from (see the pending-badge derivation // renderContainers).
// comment in renderContainers), so the separate no-tint `pending`
// class from before that removal is gone rather than kept as a
// class that would now always co-occur with this one.
const li = el('li', { const li = el('li', {
class: 'container-row' class: 'container-row'
+ (opRunning ? ' pending-running' : '') + (opRunning ? ' pending-running' : '')
@ -348,9 +334,7 @@ function buildContainerLi(c, node, opts) {
// Topology: depth contributes left-padding; the glyph string in // Topology: depth contributes left-padding; the glyph string in
// the .tree-prefix span draws the ├─ / └─ joint + continuation // the .tree-prefix span draws the ├─ / └─ joint + continuation
// lines (`│ `) for ancestors whose subtree extends below this // lines (`│ `) for ancestors whose subtree extends below this
// row. Both are CSS-driven from the data attributes so the // row. A depth-0 row gets neither — no glyph, no indent.
// legacy flat layout (every container at depth 0) is bit-
// identical to today's render — no glyph, no indent.
if (node.depth > 0) li.dataset.depth = String(node.depth); if (node.depth > 0) li.dataset.depth = String(node.depth);
const prefix = treePrefixDom(node); const prefix = treePrefixDom(node);
if (prefix) li.prepend(prefix); if (prefix) li.prepend(prefix);
@ -615,9 +599,7 @@ export function renderContainers(s) {
)); ));
} }
// Queue-summary banner lives outside this section now — see // Queue-summary banner: see initJobqRollup, above.
// #jobq-rollup-section / initJobqRollup, mounted once rather than
// rebuilt on every render this function does.
if (!containers.length && !transientsState.size) { if (!containers.length && !transientsState.size) {
root.append(el('p', { class: 'empty' }, 'no managed containers')); root.append(el('p', { class: 'empty' }, 'no managed containers'));

View file

@ -89,15 +89,11 @@ window.marked = marked;
// opts out via `data-no-refresh` (its mutation arrives via an SSE event). // opts out via `data-no-refresh` (its mutation arrives via an SSE event).
bindAsyncForms(() => refreshState()); bindAsyncForms(() => refreshState());
// Live ticker for approval request-age chips. Approval cards only // One ticker feeds two live displays that would otherwise only
// re-render on `approval_added`/`approval_resolved` SSE events, so // update on the next SSE-triggered re-render: approval request-age
// a request pending for an hour could still show "0s ago" without // chips (`.approval-ts`, flips `.stale` at the 1h mark) and schedule
// this ticker. Also flips `.stale` (amber highlight) at exactly 1h // next-fire countdowns (`.sched-due`, stamped with `data-due-at` by
// rather than only at the next re-render. // the renderers so this loop can refresh them without a full re-render).
// Live countdown for schedule next-fire cells. Renderers stamp
// `data-due-at` on `.sched-due` elements so this single ticker keeps
// them fresh without triggering a full re-render. Also keeps
// `.approval-ts` stale-highlight fresh at the 1h boundary.
setInterval(() => { setInterval(() => {
const now = Math.floor(Date.now() / 1000); const now = Math.floor(Date.now() / 1000);
document.querySelectorAll('.approval-ts[data-requested-at]').forEach((node) => { document.querySelectorAll('.approval-ts[data-requested-at]').forEach((node) => {
@ -188,8 +184,6 @@ window.marked = marked;
// names from here instead of refetching on every keystroke). // names from here instead of refetching on every keystroke).
window.__hyperhive_state = s; window.__hyperhive_state = s;
renderServerWarnings(s.server_warnings); renderServerWarnings(s.server_warnings);
// (The M4TR1X surface is reachable directly at /matrix/ when enabled
// — no link in the dashboard tab strip or the H0M3 hub.)
// Hive identity: render the swarm/hive name as a headline at the // Hive identity: render the swarm/hive name as a headline at the
// top of the SW4RM pane + update the page title once the // top of the SW4RM pane + update the page title once the
// server-side display names are known. `hive_name` / `swarm_name` // server-side display names are known. `hive_name` / `swarm_name`
@ -228,8 +222,6 @@ window.marked = marked;
// Sync the derived approvals store from the snapshot, then // Sync the derived approvals store from the snapshot, then
// render. Live `*_added` / `*_resolved` events mutate the store // render. Live `*_added` / `*_resolved` events mutate the store
// directly and re-render without a snapshot refetch. // directly and re-render without a snapshot refetch.
// (renderInbox now lives in ./flow.js — dashboard has no
// #inbox-section element to render into.)
syncApprovalsFromSnapshot(s); syncApprovalsFromSnapshot(s);
renderApprovals(); renderApprovals();
refreshSchedules(); refreshSchedules();
@ -289,8 +281,6 @@ window.marked = marked;
transient_cleared: applyTransientCleared, transient_cleared: applyTransientCleared,
container_state_changed: applyContainerStateChanged, container_state_changed: applyContainerStateChanged,
container_removed: applyContainerRemoved, container_removed: applyContainerRemoved,
// tombstones_changed / meta_inputs_changed / meta_update_running are
// handled on /core.html now (the SYST3M panels moved there).
// rebuild_queue_changed: refreshes the SW4RM queue-summary banner // rebuild_queue_changed: refreshes the SW4RM queue-summary banner
// (see swarm.js) — a payload-less push trigger, same treatment // (see swarm.js) — a payload-less push trigger, same treatment
// /builds.html gives it for its JobqGraph mount handle's .refresh() // /builds.html gives it for its JobqGraph mount handle's .refresh()
@ -383,11 +373,6 @@ window.marked = marked;
if (target === 'call') { refreshOperatorInbox(); } if (target === 'call') { refreshOperatorInbox(); }
} }
// ST4TS (hive-wide turn-stats rollup) moved to its own page,
// `/stats.html` — the render JS + the window selector live in
// stats.js now. The dashboard no longer fetches
// /api/stats-hive.
// Wire the shared tab strip now that activateTab + the lazy-load fns it // Wire the shared tab strip now that activateTab + the lazy-load fns it
// calls are defined. The strip resolves the active tab from the hash // calls are defined. The strip resolves the active tab from the hash
// (default SW4RM), toggles the active tab/pane + aria-selected, and // (default SW4RM), toggles the active tab/pane + aria-selected, and
@ -404,10 +389,6 @@ window.marked = marked;
// stores so SSE-driven updates flow through without extra plumbing. // stores so SSE-driven updates flow through without extra plumbing.
// Set `hidden` when the count is zero so the pill doesn't draw // Set `hidden` when the count is zero so the pill doesn't draw
// attention to an empty room. // attention to an empty room.
// The operator inbox (unread agent->operator messages) now lives in
// call.js — `refreshOperatorInbox`, `operatorInboxAppendFromEvent`, and
// `operatorInboxCount` are imported above. It calls back through the
// `onCountsChanged` callback registered via `initCall` at boot.
function setTabCount(tab, n) { function setTabCount(tab, n) {
const el_ = $('tab-count-' + tab); const el_ = $('tab-count-' + tab);