From 4c37ce91500f60428182cc7b9c500f3c4afa87b3 Mon Sep 17 00:00:00 2001 From: iris Date: Sat, 1 Aug 2026 11:30:36 +0200 Subject: [PATCH] dashboard: consolidate NodeView.has_log into build_log_id Per mara's review on #2896: has_log: bool was fully redundant once build_log_id: Option existed alongside it (has_log was always just build_log_id.is_some()). Dropped has_log, threading the single Option field through job_queue::mod.rs, the hivectl NodeView test-helper literal, and the one remaining frontend consumer (findLiveBuild's live-log-panel gate, which now checks build_log_id != null instead of the separate bool). Also fixed a now-stale doc comment on GET /api/build-log/{node_id} that claimed the dashboard used on-demand node-id fetches "instead of an inline build_log_id on the wire" -- no longer true after this PR put one there for the BUILD L0GS deep-link. cargo build/clippy/test clean across the three touched crates; nix fmt clean; frontend build verified (0 has_log references, 3 build_log_id references in the built builds.js bundle). --- frontend/packages/dashboard/src/builds.js | 4 ++-- hive-c0re/src/dashboard/build_logs.rs | 8 +++++--- hive-c0re/src/job_queue/mod.rs | 2 -- hive-host-sock/src/jobs.rs | 16 ++++++---------- hivectl/src/dag_progress.rs | 1 - 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/frontend/packages/dashboard/src/builds.js b/frontend/packages/dashboard/src/builds.js index 04a77ded..b3c5fc0f 100644 --- a/frontend/packages/dashboard/src/builds.js +++ b/frontend/packages/dashboard/src/builds.js @@ -444,11 +444,11 @@ function clearLiveLogPoll() { } // First (entry, node) pair with a running node that has a log. -// Gate on has_log so lock/noop/store-only nodes don't open a blank panel. +// Gate on build_log_id so lock/noop/store-only nodes don't open a blank panel. function findLiveBuild(queue) { for (const e of queue || []) { if (rollupState(e.nodes || []) !== 'Running') continue; - const node = (e.nodes || []).find((n) => n.state === 'Running' && n.has_log); + const node = (e.nodes || []).find((n) => n.state === 'Running' && n.build_log_id != null); if (node) return { entry: e, node }; } return null; diff --git a/hive-c0re/src/dashboard/build_logs.rs b/hive-c0re/src/dashboard/build_logs.rs index 7c741a52..27489263 100644 --- a/hive-c0re/src/dashboard/build_logs.rs +++ b/hive-c0re/src/dashboard/build_logs.rs @@ -130,9 +130,11 @@ pub(super) async fn get_build_log_full( /// `GET /api/build-log/{node_id}` — the build log for a **queue node**, /// resolved node id → log-row id → full log. Same `BuildLogFull` JSON /// (`stdout` / `stderr` + header) as `get_build_log_full`; HTTP 404 when the -/// node has no linked log (the client gates the request on `NodeView.has_log`, -/// but a vacuum race can still 404). This is the on-demand log fetch the -/// raw-graph dashboard uses instead of an inline `build_log_id` on the wire. +/// node has no linked log (the client gates the request on +/// `NodeView.build_log_id`, but a vacuum race can still 404). This is the +/// on-demand live-log-panel fetch, distinct from the `build_log_id` on the +/// wire — that id is for deep-linking to the BUILD L0GS tab's full history +/// view, not for fetching the log content itself. #[utoipa::path( get, path = "/api/build-log/{node_id}", diff --git a/hive-c0re/src/job_queue/mod.rs b/hive-c0re/src/job_queue/mod.rs index 3cb8efd2..2af5c84e 100644 --- a/hive-c0re/src/job_queue/mod.rs +++ b/hive-c0re/src/job_queue/mod.rs @@ -560,7 +560,6 @@ impl QueueInner { Vec::new() }; let build_log_id = self.node_rt.get(&id).and_then(|r| r.build_log_id); - let has_log = build_log_id.is_some(); // `node.parent` is the structural jobq parent. Top-level nodes // have `parent == Some(container)` (direct children of the Dag // container); those become `parent: None` on the wire since the @@ -581,7 +580,6 @@ impl QueueInner { error: node.error.clone(), approval_id, inputs, - has_log, build_log_id, parent, }); diff --git a/hive-host-sock/src/jobs.rs b/hive-host-sock/src/jobs.rs index 50394821..feba036f 100644 --- a/hive-host-sock/src/jobs.rs +++ b/hive-host-sock/src/jobs.rs @@ -105,16 +105,12 @@ pub struct NodeView { /// node. Display-only payload, not derivable from the graph. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub inputs: Vec, - /// Whether this node has a captured build log fetchable at - /// `GET /api/build-log/`. Only the nix-heavy nodes that stream build - /// output set one; the client gates its log link on this so lock / noop / - /// store-only nodes don't render a link that 404s. - #[serde(default)] - pub has_log: bool, - /// The underlying build-log history row id, when this node has a - /// captured log (`Some` iff `has_log`). Lets the client deep-link to the - /// rich BUILD L0GS tab view (`/builds.html?id=#buildlogs`) instead of - /// only the raw-text download endpoint. + /// The build-log history row id, when this node has a captured build + /// log fetchable at `GET /api/build-log/` and deep-linkable to + /// `/builds.html?id=#buildlogs`. Only the nix-heavy nodes that + /// stream build output set one; the client gates its log link on + /// `.is_some()` so lock / noop / store-only nodes don't render a link + /// that 404s. #[serde(default, skip_serializing_if = "Option::is_none")] pub build_log_id: Option, /// Structural parent in the jobq tree — `None` for top-level nodes diff --git a/hivectl/src/dag_progress.rs b/hivectl/src/dag_progress.rs index 059b8c11..aaca5710 100644 --- a/hivectl/src/dag_progress.rs +++ b/hivectl/src/dag_progress.rs @@ -342,7 +342,6 @@ mod tests { error: None, approval_id: None, inputs: vec![], - has_log: false, build_log_id: None, } }