Compare commits

...
Author SHA1 Message Date
iris
abffa5234d fix(#2854): slice the store-path hash from the front, not the pname suffix from the back
current_flake_rev canonicalizes to /nix/store/<hash>-<pname>; the
hash right after /nix/store/ is what varies between builds, the
trailing -<pname> 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.
2026-07-31 19:37:41 +02:00
iris
761f4b8351 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.
2026-07-31 19:32:20 +02:00
3 changed files with 29 additions and 0 deletions

View file

@ -48,6 +48,26 @@ 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.
//
// `current_flake_rev` canonicalizes to a nix store path
// (/nix/store/<hash>-<pname>) — the part that actually varies between
// builds is the hash right after `/nix/store/`, not the trailing
// `-<pname>` (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 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;
}
}
init();

View file

@ -30,6 +30,7 @@
<header class="home-header">
<p class="banner-thin" id="hive-identity" hidden></p>
<pre class="banner">░▒▓█▓▒░ ░▒▓█▓▒░ H Y P E R H I V E · H0M3 ░▒▓█▓▒░ ░▒▓█▓▒░</pre>
<p class="banner-thin" id="hive-rev" hidden></p>
</header>
<main class="home-main">

View file

@ -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<String>,
any_stale: bool,
containers: Vec<ContainerView>,
transients: Vec<TransientView>,
@ -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,