From 7c6f108716c64c8d384501ceacd009a06eb7c814 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 3 Aug 2026 00:37:39 +0200 Subject: [PATCH] coordinator: push_todo returns Result so callers can see delivery outcome --- hive-c0re/src/actions.rs | 8 +++---- hive-c0re/src/coordinator.rs | 22 ++++++++++++++----- hive-c0re/src/job_queue/exec.rs | 4 ++-- hive-c0re/src/server.rs | 4 ++-- .../src/socket_server/lifecycle_handlers.rs | 2 +- hive-c0re/src/workers/crash_watch.rs | 4 ++-- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/hive-c0re/src/actions.rs b/hive-c0re/src/actions.rs index 602b3990..62c04aaa 100644 --- a/hive-c0re/src/actions.rs +++ b/hive-c0re/src/actions.rs @@ -739,7 +739,7 @@ async fn finish_approval( match approval.kind { ApprovalKind::InitConfig => { if ok { - coord + let _ = coord .push_todo_submitter( approval.id, "core", @@ -763,7 +763,7 @@ async fn finish_approval( note.as_deref().unwrap_or("unknown error") ) }; - coord + let _ = coord .push_todo_submitter( approval.id, "core", @@ -784,7 +784,7 @@ async fn finish_approval( approval.fetched_sha.as_deref(), terminal_tag.as_deref(), ); - coord + let _ = coord .push_todo_submitter( approval.id, "core", @@ -963,7 +963,7 @@ pub async fn destroy(coord: &Arc, name: &str, purge: bool) -> Resul tracing::warn!(%name, error = ?e, "agent_power: remove on destroy failed"); } drop(guard); - coord + let _ = coord .push_todo( hive_sh4re::MANAGER_AGENT, "core", diff --git a/hive-c0re/src/coordinator.rs b/hive-c0re/src/coordinator.rs index 80686842..4998e441 100644 --- a/hive-c0re/src/coordinator.rs +++ b/hive-c0re/src/coordinator.rs @@ -1387,6 +1387,14 @@ impl Coordinator { /// delivery. An agent that's down doesn't need a todo about /// something it'll never see appear this way; whatever mechanism /// resurfaces its state on the next boot is unrelated to this path. + /// + /// Returns `Ok(())` on a successful push and `Err(reason)` — a + /// short human-readable string, already logged at `debug`/`warn` + /// by this function — on any of the silent-no-op cases below. + /// Most callers are pure fire-and-forget notices and ignore it + /// (`let _ = coord.push_todo(...).await;`); callers that track a + /// per-target delivery outcome (e.g. the scheduled-prompts worker's + /// `last_result` column) use it instead of assuming success. pub async fn push_todo( &self, agent: &str, @@ -1394,15 +1402,15 @@ impl Coordinator { key: Option, summary: String, source: Option, - ) { + ) -> Result<(), String> { let Ok(ident) = hive_types::Ident::parse(agent) else { tracing::warn!(%agent, "push_todo: not a valid agent ident, skipping"); - return; + return Err(format!("'{agent}' is not a valid agent ident")); }; let path = hive_host_sock::agent_todo_socket(&ident); if !path.exists() { tracing::debug!(%agent, path = %path.display(), "push_todo: agent socket not present (offline?), skipping"); - return; + return Err(format!("agent '{agent}' socket not present (offline?)")); } let req = hive_agent_sock::Request::UpsertTodo { subsystem: subsystem.to_owned(), @@ -1419,11 +1427,13 @@ impl Coordinator { { Ok(hive_agent_sock::Response::Err { message }) => { tracing::warn!(%agent, %message, "push_todo: agent rejected the todo"); + Err(format!("agent '{agent}' rejected the todo: {message}")) } Err(e) => { tracing::warn!(%agent, error = ?e, "push_todo: dial failed"); + Err(format!("push_todo dial to '{agent}' failed: {e:#}")) } - Ok(_) => {} + Ok(_) => Ok(()), } } @@ -1436,10 +1446,10 @@ impl Coordinator { key: Option, summary: String, source: Option, - ) { + ) -> Result<(), String> { let target = self.submitter_or_manager(approval_id); self.push_todo(&target, subsystem, key, summary, source) - .await; + .await } /// Push a `HelperEvent` into an arbitrary agent's inbox. Encoded diff --git a/hive-c0re/src/job_queue/exec.rs b/hive-c0re/src/job_queue/exec.rs index 5208a43f..f6dc3560 100644 --- a/hive-c0re/src/job_queue/exec.rs +++ b/hive-c0re/src/job_queue/exec.rs @@ -152,7 +152,7 @@ async fn run_emit_rebuilt(coord: &Arc, agent: &str, dag_id: Option< .then(|| dag_id.and_then(|dag| coord.job_queue.first_error(dag))) .flatten(); let summary = crate::coordinator::rebuilt_todo_summary(agent, ok, note.as_deref(), None, None); - coord + let _ = coord .push_todo( hive_sh4re::MANAGER_AGENT, "core", @@ -429,7 +429,7 @@ async fn run_stop(coord: &Arc, name: &str) -> Result<()> { // own kind now. crate::lifecycle::kill(name).await?; coord.unregister_agent(name); - coord + let _ = coord .push_todo( hive_sh4re::MANAGER_AGENT, "core", diff --git a/hive-c0re/src/server.rs b/hive-c0re/src/server.rs index 826d59fc..b9caf19f 100644 --- a/hive-c0re/src/server.rs +++ b/hive-c0re/src/server.rs @@ -297,7 +297,7 @@ async fn handle_spawn(coord: &Arc, name: &str) -> Result, name: &str) -> Result { // Spawn failed: register_agent was never called, so there is // nothing to unregister. Notify the manager and propagate. - coord + let _ = coord .push_todo( hive_sh4re::MANAGER_AGENT, "core", diff --git a/hive-c0re/src/socket_server/lifecycle_handlers.rs b/hive-c0re/src/socket_server/lifecycle_handlers.rs index 0b7449ad..46446c12 100644 --- a/hive-c0re/src/socket_server/lifecycle_handlers.rs +++ b/hive-c0re/src/socket_server/lifecycle_handlers.rs @@ -129,7 +129,7 @@ pub(super) async fn handle_kill(coord: &Arc, agent: &str, name: &st .await; match result { Ok(()) => { - coord + let _ = coord .push_todo( hive_sh4re::MANAGER_AGENT, "core", diff --git a/hive-c0re/src/workers/crash_watch.rs b/hive-c0re/src/workers/crash_watch.rs index df41815f..3cd704ee 100644 --- a/hive-c0re/src/workers/crash_watch.rs +++ b/hive-c0re/src/workers/crash_watch.rs @@ -132,7 +132,7 @@ async fn emit_login_transitions( ) { for agent in current.difference(prev) { tracing::info!(%agent, "agent logged in"); - coord + let _ = coord .push_todo( hive_sh4re::MANAGER_AGENT, "core", @@ -163,7 +163,7 @@ async fn emit_login_transitions( .collect(); for agent in current_needs.difference(&prev_needs) { tracing::info!(%agent, "agent needs login"); - coord + let _ = coord .push_todo( hive_sh4re::MANAGER_AGENT, "core",