hive-c0re: push HelperEvent::Spawned as a todo, not a broker message

Follow-up from #2955 (mara: 'make core able to give agent a todo').
First migration slice: Spawned was pure FYI-check-when-convenient
material, not something needing an immediate turn.

Coordinator::push_todo/push_todo_submitter do a best-effort live dial
of the target agent's own hive-agent-sock (hive_host_sock::agent_todo_
socket), sending the exact UpsertTodo request in-container producers
(matrix/bash/forge-notify) already send. Push, not queue: agent
offline (socket absent) or dial failure is a silent no-op, no retry,
no fallback delivery -- matches mara's 'not available if offline'
call exactly.

HelperEvent::Spawned removed entirely (enum variant + all 3 call
sites migrated: handle_spawn's two arms, finish_approval's Spawn
approval-kind arm) rather than kept alongside a translation layer --
per mara's correction on the first design attempt, migrating the
producer means deleting the old path, not bridging it.

Verified: cargo build/clippy/test -p hive-c0re -p hive-host-sock
-p hive-sh4re clean (318 tests), nix fmt clean.
This commit is contained in:
damocles 2026-08-02 22:47:47 +02:00 committed by mara
commit d77f81cd1e
8 changed files with 150 additions and 37 deletions

View file

@ -498,7 +498,7 @@ async fn run_approval_schedule_prompt(
.context("insert scheduled prompt")
}
.await;
finish_approval(coord, &approval, result, None)
finish_approval(coord, &approval, result, None).await
}
/// Resolve an approval row from how its DAG's work ended — the body of the
@ -565,7 +565,7 @@ pub(crate) async fn resolve_approval_dag(
}
_ => {}
}
if let Err(e) = finish_approval(coord, &approval, result, terminal_tag) {
if let Err(e) = finish_approval(coord, &approval, result, terminal_tag).await {
tracing::warn!(approval_id, error = ?e, "approval dag resolved with failure");
}
}
@ -682,10 +682,10 @@ async fn run_approval_init_config(
{
tracing::warn!(agent = %approval.agent, error = ?e, "forge: ensure_meta_remote after init_config failed");
}
finish_approval(coord, &approval, result, None)
finish_approval(coord, &approval, result, None).await
}
fn finish_approval(
async fn finish_approval(
coord: &Coordinator,
approval: &hive_sh4re::Approval,
result: Result<()>,
@ -747,14 +747,26 @@ fn finish_approval(
);
}
}
ApprovalKind::Spawn => coord.notify_submitter(
approval.id,
&HelperEvent::Spawned {
agent: approval.agent.to_string(),
ok,
note,
},
),
ApprovalKind::Spawn => {
let summary = if ok {
format!("agent '{}' spawned", approval.agent)
} else {
format!(
"agent '{}' spawn FAILED: {}",
approval.agent,
note.as_deref().unwrap_or("unknown error")
)
};
coord
.push_todo_submitter(
approval.id,
"core",
Some(format!("spawned:{}", approval.agent)),
summary,
None,
)
.await;
}
// MergeConfigPr ends in a container rebuild — surface a Rebuilt
// lifecycle event. (It is never a first spawn — the agent already
// exists — so it never needs the Spawned arm above.)