From 761f4b835101d89b593480dba51caafaa275fd85 Mon Sep 17 00:00:00 2001 From: iris Date: Fri, 31 Jul 2026 19:32:20 +0200 Subject: [PATCH 1/2] dashboard: surface the hive's hyperhive rev on the H0M3 start page Adds hyperhive_rev to the dashboard's /api/state StateSnapshot, resolved via the same current_flake_rev helper get_agent_meta's per-agent hyperhive_rev already uses. home.js renders it next to the existing hive-identity line, truncated to the last 12 chars with the full value in title=, hidden when the flake ref isn't a local path pin. Requested by annika (infra.run) via dmatrix, hyperhive#2854. --- frontend/packages/dashboard/src/home.js | 13 +++++++++++++ frontend/packages/dashboard/src/index.html | 1 + hive-c0re/src/dashboard/state_snapshot.rs | 8 ++++++++ 3 files changed, 22 insertions(+) diff --git a/frontend/packages/dashboard/src/home.js b/frontend/packages/dashboard/src/home.js index 70b13dc6..0dead042 100644 --- a/frontend/packages/dashboard/src/home.js +++ b/frontend/packages/dashboard/src/home.js @@ -48,6 +48,19 @@ async function init() { ident.textContent = parts.join(' / '); ident.hidden = false; } + + // Rev line: absent when the flake ref isn't a local path pin (a bare + // `github:` url has no on-disk rev to canonicalize) — hidden rather + // than showing a placeholder in that case. + const rev = $('hive-rev'); + if (rev && state.hyperhive_rev) { + const short = state.hyperhive_rev.length > 16 + ? `…${state.hyperhive_rev.slice(-12)}` + : state.hyperhive_rev; + rev.textContent = `rev ${short}`; + rev.title = state.hyperhive_rev; + rev.hidden = false; + } } init(); diff --git a/frontend/packages/dashboard/src/index.html b/frontend/packages/dashboard/src/index.html index c6b98a8a..cabbc40a 100644 --- a/frontend/packages/dashboard/src/index.html +++ b/frontend/packages/dashboard/src/index.html @@ -30,6 +30,7 @@
+
diff --git a/hive-c0re/src/dashboard/state_snapshot.rs b/hive-c0re/src/dashboard/state_snapshot.rs index ff23cb98..14d96eb6 100644 --- a/hive-c0re/src/dashboard/state_snapshot.rs +++ b/hive-c0re/src/dashboard/state_snapshot.rs @@ -37,6 +37,13 @@ pub(super) struct StateSnapshot { /// "apply everything you've buffered". seq: u64, hostname: String, + /// Current rev of the pinned `hyperhive` flake input, resolved the + /// same way `get_agent_meta`'s per-agent `hyperhive_rev` is (see + /// `auto_update::current_flake_rev`). `None` when the flake ref + /// isn't a local path pin (e.g. a bare `github:` url) or the rev + /// can't be resolved. Feeds the dashboard start page so an operator + /// can tell what build a hive is running without shelling in. + hyperhive_rev: Option, any_stale: bool, containers: Vec, transients: Vec, @@ -382,6 +389,7 @@ pub(super) async fn api_state( axum::Json(StateSnapshot { seq, hostname, + hyperhive_rev: crate::auto_update::current_flake_rev(&state.coord.hyperhive_flake), any_stale, containers, transients, From abffa5234daa9340e7452adb9269e19c016418ee Mon Sep 17 00:00:00 2001 From: iris Date: Fri, 31 Jul 2026 19:37:41 +0200 Subject: [PATCH 2/2] fix(#2854): slice the store-path hash from the front, not the pname suffix from the back current_flake_rev canonicalizes to /nix/store/-; the hash right after /nix/store/ is what varies between builds, the trailing - is constant. slice(-12) was taking the tail, so two different builds would very likely render the same truncated string. slice the hash prefix out instead, with a plain head-slice fallback for a non-store-path rev (e.g. a bare local dir in dev). damocles caught this in review on PR #2869. --- frontend/packages/dashboard/src/home.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/frontend/packages/dashboard/src/home.js b/frontend/packages/dashboard/src/home.js index 0dead042..fc4918e1 100644 --- a/frontend/packages/dashboard/src/home.js +++ b/frontend/packages/dashboard/src/home.js @@ -52,11 +52,18 @@ async function init() { // Rev line: absent when the flake ref isn't a local path pin (a bare // `github:` url has no on-disk rev to canonicalize) — hidden rather // than showing a placeholder in that case. + // + // `current_flake_rev` canonicalizes to a nix store path + // (/nix/store/-) — the part that actually varies between + // builds is the hash right after `/nix/store/`, not the trailing + // `-` (constant across revs). Slice the hash out of the front + // rather than truncating from the tail, so two different builds don't + // render as the same string. Falls back to a plain head-slice for a + // non-store path (e.g. a bare local dir during dev). const rev = $('hive-rev'); if (rev && state.hyperhive_rev) { - const short = state.hyperhive_rev.length > 16 - ? `…${state.hyperhive_rev.slice(-12)}` - : state.hyperhive_rev; + const storeMatch = state.hyperhive_rev.match(/^\/nix\/store\/([^-]+)/); + const short = storeMatch ? storeMatch[1].slice(0, 12) : state.hyperhive_rev.slice(0, 12); rev.textContent = `rev ${short}`; rev.title = state.hyperhive_rev; rev.hidden = false;