From 836284a22dbd5105bf8f7e682523f9734d099b74 Mon Sep 17 00:00:00 2001 From: damocles Date: Sun, 2 Aug 2026 23:47:11 +0200 Subject: [PATCH] coordinator: add push_todo mechanism for host-to-agent lifecycle notices --- hive-c0re/src/coordinator.rs | 79 ++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/hive-c0re/src/coordinator.rs b/hive-c0re/src/coordinator.rs index 67446c2a..80686842 100644 --- a/hive-c0re/src/coordinator.rs +++ b/hive-c0re/src/coordinator.rs @@ -1613,3 +1613,82 @@ impl Coordinator { .collect() } } + +/// `push_todo`/`push_todo_submitter` summary text for a rebuild outcome — +/// shared by the two `Rebuilt` call sites (`actions::finish_approval`'s +/// `MergeConfigPr` arm, `job_queue::exec::run_emit_rebuilt`) so the wording +/// stays identical regardless of which path fired. Pure + independently +/// testable, unlike the old `HelperEvent::Rebuilt`'s separate `sha`/`tag` +/// fields — those become part of the summary text itself now, since a todo +/// carries one string, not a structured payload. +#[must_use] +pub fn rebuilt_todo_summary( + agent: &str, + ok: bool, + note: Option<&str>, + sha: Option<&str>, + tag: Option<&str>, +) -> String { + use std::fmt::Write as _; + + if !ok { + return format!( + "agent '{agent}' rebuild FAILED: {}", + note.unwrap_or("unknown error") + ); + } + + let mut summary = format!("agent '{agent}' rebuilt"); + if let Some(sha) = sha { + let _ = write!(summary, " @ {sha}"); + } + if let Some(tag) = tag { + let _ = write!(summary, " ({tag})"); + } + summary +} + +#[cfg(test)] +mod rebuilt_todo_summary_tests { + use super::rebuilt_todo_summary; + + #[test] + fn failure_reports_the_note() { + assert_eq!( + rebuilt_todo_summary("iris", false, Some("build failed"), None, None), + "agent 'iris' rebuild FAILED: build failed" + ); + } + + #[test] + fn failure_without_a_note_says_unknown() { + assert_eq!( + rebuilt_todo_summary("iris", false, None, None, None), + "agent 'iris' rebuild FAILED: unknown error" + ); + } + + #[test] + fn success_with_no_sha_or_tag_is_bare() { + assert_eq!( + rebuilt_todo_summary("iris", true, None, None, None), + "agent 'iris' rebuilt" + ); + } + + #[test] + fn success_with_sha_and_tag_carries_both() { + assert_eq!( + rebuilt_todo_summary("iris", true, None, Some("abc123"), Some("deployed/42")), + "agent 'iris' rebuilt @ abc123 (deployed/42)" + ); + } + + #[test] + fn success_with_sha_only() { + assert_eq!( + rebuilt_todo_summary("iris", true, None, Some("abc123"), None), + "agent 'iris' rebuilt @ abc123" + ); + } +}