diff --git a/hive-c0re/src/actions.rs b/hive-c0re/src/actions.rs index 877543f6..9036b2bd 100644 --- a/hive-c0re/src/actions.rs +++ b/hive-c0re/src/actions.rs @@ -89,7 +89,7 @@ pub async fn approve(coord: Arc, id: i64) -> Result<()> { let inputs: Vec = serde_json::from_str(&approval.commit_ref).unwrap_or_default(); let result = crate::meta::lock_update(&inputs).await; - finish_approval(&coord, &approval, result, None, false) + finish_approval(&coord, &approval, result, None) } ApprovalKind::Spawn => { // Run the spawn in the background so the approve POST returns diff --git a/hive-c0re/src/crash_watch.rs b/hive-c0re/src/crash_watch.rs index 99bd3b01..a23083e3 100644 --- a/hive-c0re/src/crash_watch.rs +++ b/hive-c0re/src/crash_watch.rs @@ -30,7 +30,6 @@ pub fn spawn(coord: Arc) { tokio::spawn(async move { let mut prev_running: HashSet = HashSet::new(); let mut prev_logged_in: HashSet = HashSet::new(); - let mut prev_sub_agents: HashSet = HashSet::new(); let mut seeded = false; loop { let raw = lifecycle::list().await.unwrap_or_default(); @@ -60,13 +59,7 @@ pub fn spawn(coord: Arc) { if seeded { emit_crash_transitions(&coord, &prev_running, ¤t_running); - emit_login_transitions( - &coord, - &prev_logged_in, - ¤t_logged_in, - &sub_agents, - &prev_sub_agents, - ); + emit_login_transitions(&coord, &prev_logged_in, ¤t_logged_in, &sub_agents); } // Periodic container rescan — catches state flips that // happen outside our mutation surface (operator runs @@ -76,7 +69,6 @@ pub fn spawn(coord: Arc) { coord.rescan_containers_and_emit().await; prev_running = current_running; prev_logged_in = current_logged_in; - prev_sub_agents = sub_agents.into_iter().collect(); seeded = true; tokio::select! { @@ -118,7 +110,6 @@ fn emit_login_transitions( prev: &HashSet, current: &HashSet, sub_agents: &[String], - prev_sub_agents: &HashSet, ) { for agent in current.difference(prev) { tracing::info!(%agent, "agent logged in"); @@ -126,16 +117,13 @@ fn emit_login_transitions( agent: agent.clone(), }); } - // Detect transitions into "needs login": an agent that was previously - // logged-in goes unsigned (credentials deleted), OR a brand-new agent - // appears without a session. - // - // prev_needs uses prev_sub_agents (the agent set from the last tick) so - // that a newly-spawned agent — which does not appear in prev_sub_agents — - // is absent from prev_needs even though it's not in prev_logged_in. - // Without this, new agents land in both prev_needs and current_needs and - // the set difference is empty, silently dropping the event. - let prev_needs: HashSet<&str> = prev_sub_agents + // Only count NeedsLogin transitions for agents that exist and + // are *not* logged in — the difference set above already gives + // us "was in prev, gone from current" but we also want to fire + // for agents that newly appeared as not-logged-in (post-spawn / + // post-purge). Treat sub_agents minus current as the + // currently-needs-login set; emit when an agent enters it. + let prev_needs: HashSet<&str> = sub_agents .iter() .map(String::as_str) .filter(|n| !prev.contains(*n))