hive-c0re/container_view.rs: scrub attribution cookies (#715 batch 4)

This commit is contained in:
damocles 2026-05-31 17:20:32 +02:00 committed by mara
commit 0b3aa5391e

View file

@ -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<u64>,
/// 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<i64>,
/// 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<String>,
}
@ -103,8 +103,8 @@ pub async fn build_all(coord: &Coordinator) -> Vec<ContainerView> {
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<ContainerView> {
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<String>, Option<i64>) {
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<String>, Option<i64>) {
}
/// 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<String>, Option<i64>,
/// 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.