From 0b3aa5391eef660a519dc6ccf64d0638cc95bb01 Mon Sep 17 00:00:00 2001 From: damocles Date: Sun, 31 May 2026 17:20:32 +0200 Subject: [PATCH] hive-c0re/container_view.rs: scrub attribution cookies (#715 batch 4) --- hive-c0re/src/container_view.rs | 47 ++++++++++++++++----------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/hive-c0re/src/container_view.rs b/hive-c0re/src/container_view.rs index c0757b89..bd5571e0 100644 --- a/hive-c0re/src/container_view.rs +++ b/hive-c0re/src/container_view.rs @@ -61,7 +61,7 @@ pub struct ContainerView { /// config. Lets the dashboard derive the ctx badge thresholds /// (75% / 50% of the window, matching the harness compaction /// watermarks) instead of hardcoding them. `None` when the agent - /// has no turns yet or no config key matches the model. (issue #66) + /// has no turns yet or no config key matches the model. #[serde(default, skip_serializing_if = "Option::is_none")] pub context_window_tokens: Option, /// True while the harness is parked after an API rate-limit response. @@ -87,12 +87,12 @@ pub struct ContainerView { /// status is set. #[serde(default, skip_serializing_if = "Option::is_none")] pub status_set_at: Option, - /// Name of this agent's parent in the agent hierarchy (#361). `None` + /// Name of this agent's parent in the agent hierarchy. `None` /// marks the agent as root-level; the dashboard renders it without /// indentation. Sourced from `meta/topology.json` (single source of /// truth, hive-c0re-owned) — NOT from per-agent agent.nix, because /// an agent shouldn't be able to unilaterally declare its own place - /// in the tree. + /// in the tree. See `docs/agent-hierarchy.md::Current state`. #[serde(default, skip_serializing_if = "Option::is_none")] pub parent: Option, } @@ -103,8 +103,8 @@ pub async fn build_all(coord: &Coordinator) -> Vec { let raw = lifecycle::list().await.unwrap_or_default(); let locked = read_meta_locked_revs(); // Pull the topology map once and look up each agent's parent below. - // Empty / absent topology.json → every agent root-level (matches - // the pre-#361 status quo for fresh installs). + // Empty / absent topology.json → every agent root-level (safe + // degradation for fresh installs that haven't run sync_agents yet). let topology = crate::topology::read(); let mut out = Vec::new(); for c in &raw { @@ -135,21 +135,21 @@ pub async fn build_all(coord: &Coordinator) -> Vec { let extra_links = read_dashboard_links(&logical); let parent = topology.get(&logical).cloned().flatten(); let running = lifecycle::is_running(&logical).await; - // Live-only fields (#432) — only meaningful while the harness - // is up. When the container is stopped, sentinel files + - // turn-stats rows + the on-disk status blob are all stale - // snapshots from before the stop, so we clear them here - // rather than letting the dashboard / `get_agent_meta` surface - // misleading values. Static / declared fields (extra_links, - // deployed_sha, pending_reminders, needs_update, parent) stay - // populated regardless of run state. + // Live-only fields — only meaningful while the harness is up. + // When the container is stopped, sentinel files + turn-stats + // rows + the on-disk status blob are all stale snapshots from + // before the stop, so we clear them here rather than letting + // the dashboard / `get_agent_meta` surface misleading values. + // Static / declared fields (extra_links, deployed_sha, + // pending_reminders, needs_update, parent) stay populated + // regardless of run state. let (needs_login, ctx_tokens, context_window_tokens, rate_limited, status_text, status_set_at) = if running { // needs_login fires when EITHER the claude session dir is // missing (boot-time / fresh container) OR the harness wrote - // the auth-failed sentinel because a turn hit 401 (#419). The - // manager has its own session lifecycle and never participates - // in needs_login. + // the auth-failed sentinel because a turn hit 401. The + // manager has its own session lifecycle and never + // participates in needs_login. let needs_login = !is_manager && (!claude_has_session(&Coordinator::agent_claude_dir(&logical)) || auth_failed_sentinel(&logical)); @@ -224,7 +224,7 @@ fn is_rate_limited(name: &str) -> bool { /// after a 401 mid-turn. Lets the dashboard surface `needs_login` for /// agents whose `/root/.claude/` dir still exists (so /// `claude_has_session` returns true) but whose OAuth credentials -/// inside it have actually expired (#419). +/// inside it have actually expired. fn auth_failed_sentinel(name: &str) -> bool { Coordinator::agent_notes_dir(name) .join("hyperhive-needs-login") @@ -237,7 +237,7 @@ fn auth_failed_sentinel(name: &str) -> bool { /// /// NB: callers building `AgentMeta` for a *stopped* container should /// clear the result — the on-disk status is a stale snapshot from -/// before the stop (#432). Use `read_agent_status_live` for that. +/// before the stop. Use `read_agent_status_live` for that. pub fn read_agent_status(name: &str) -> (Option, Option) { let path = Coordinator::agent_notes_dir(name).join("hyperhive-status"); let meta = std::fs::metadata(&path).ok(); @@ -257,10 +257,9 @@ fn read_status(name: &str) -> (Option, Option) { } /// Wraps `read_agent_status` with the same "stopped containers have -/// stale state" gate `build_all` uses (#432). Returns -/// `(None, None, false)` when the container isn't running so callers -/// don't have to know about the sentinel rules — they just hand back -/// what we give them. +/// stale state" gate `build_all` uses. Returns `(None, None, false)` +/// when the container isn't running so callers don't have to know +/// about the sentinel rules — they just hand back what we give them. /// /// Returned tuple is `(status_text, status_set_at, running)`. The /// `name` argument is the broker-side recipient — `MANAGER_AGENT` for @@ -286,13 +285,13 @@ pub async fn read_agent_status_live(name: &str) -> (Option, Option, /// Host-side hive + swarm display names, read from the c0re service's /// own process env. The `hive-c0re.nix` module sets these from -/// `services.hyperhive.{hiveName, swarmName}` (#701). The agent-side +/// `services.hyperhive.{hiveName, swarmName}`. The agent-side /// `hive-ag3nt::identity::{hive_name, swarm_name}` accessors read the /// same env vars after they're forwarded into each sub-agent's /// harness service environment by `meta::render_flake`; surfacing /// them here from c0re's own env keeps the manager + agent /// `GetAgentMeta` paths consistent without a round-trip to the -/// target container (#710). +/// target container. /// /// Returns `(hive_name, swarm_name)`. Each is `None` when the /// corresponding env var is unset or empty.