coordinator: push_todo returns Result so callers can see delivery outcome

This commit is contained in:
damocles 2026-08-03 00:37:39 +02:00 committed by mara
commit 7c6f108716
6 changed files with 27 additions and 17 deletions

View file

@ -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<Coordinator>, 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",

View file

@ -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<String>,
summary: String,
source: Option<String>,
) {
) -> 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<String>,
summary: String,
source: Option<String>,
) {
) -> 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

View file

@ -152,7 +152,7 @@ async fn run_emit_rebuilt(coord: &Arc<Coordinator>, 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<Coordinator>, 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",

View file

@ -297,7 +297,7 @@ async fn handle_spawn(coord: &Arc<Coordinator>, name: &str) -> Result<HostRespon
// Bind the MCP listener now that the container is starting up.
// The harness connects to this socket on its first turn.
coord.register_agent(name)?;
coord
let _ = coord
.push_todo(
hive_sh4re::MANAGER_AGENT,
"core",
@ -312,7 +312,7 @@ async fn handle_spawn(coord: &Arc<Coordinator>, name: &str) -> Result<HostRespon
Err(e) => {
// 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",

View file

@ -129,7 +129,7 @@ pub(super) async fn handle_kill(coord: &Arc<Coordinator>, agent: &str, name: &st
.await;
match result {
Ok(()) => {
coord
let _ = coord
.push_todo(
hive_sh4re::MANAGER_AGENT,
"core",

View file

@ -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",