forge: wire ensure_all() boot-warn sites to the dashboard banner

Adds set_boot_warning() to stats/warnings.rs: a one-shot variant of
set_warning() for steps that run once at hive-c0re boot (no periodic
retry to observe a later success and clear the banner via WarningGuard
drop). It forgets the guard, leaking it for the life of the process —
the banner clears on the next hive-c0re restart, which is also when a
config/environment fix would take effect.

Wires every remaining tracing::warn!()-and-forget site in
forge::ensure_all() to also raise a boot warning: core user/token
provisioning, per-org seeding, the operators-team grant per org, the
core/meta repo, shared docs repo, knowledge repo (+ its local clone),
both avatar uploads, and the final nixos-container list failure.

Split the core_token.is_some() body of ensure_all() into a new
ensure_all_orgs_and_repos() helper to stay under clippy's
function-length limit.

Deliberately out of scope: sync_agent() (shared with rebuild_agent(),
different blast radius) and ci_runner::ensure_ci_runner_registered()
(its own retry logic) — matrix::ensure_all() got the same slice-by-
slice treatment.
This commit is contained in:
iris 2026-07-17 12:54:46 +02:00 committed by mara
commit f378f842ea
2 changed files with 154 additions and 50 deletions

View file

@ -103,6 +103,23 @@ pub fn snapshot() -> Vec<ServerWarning> {
.collect()
}
/// Raise a warning for a one-shot boot-time step that has no periodic
/// retry to observe a later success and clear the banner via
/// [`WarningGuard`] drop — e.g. a step inside `forge::ensure_all()`,
/// which `tokio::spawn`s once at hive-c0re startup and never runs again
/// this process. Intentionally **leaks** the guard for the life of the
/// process: the banner clears the next time hive-c0re restarts (a fresh
/// process starts with an empty registry) and re-runs the step, which is
/// exactly when a config/environment fix would take effect anyway.
///
/// Do not use this for anything that runs periodically or can be
/// retried within the same process — hold the [`WarningGuard`] (or use
/// [`crate::stats::sweep_health::SweepHealth`]) so a later success can
/// actually clear the banner instead of waiting for a restart.
pub fn set_boot_warning(kind: &'static str, level: &'static str, message: impl Into<String>) {
std::mem::forget(set_warning(kind, level, message));
}
/// RAII handle for one active warning. Drop clears the `kind` from the
/// banner. Obtained from [`set_warning`].
#[must_use = "dropping the guard immediately clears the warning; bind it for as long as the condition holds"]
@ -237,6 +254,24 @@ mod tests {
}
}
#[test]
fn boot_warning_survives_without_a_held_guard() {
// Unlike `set_warning`, `set_boot_warning` returns nothing to hold —
// the whole point is that the warning outlives the call that raised
// it (no guard in scope to drop).
set_boot_warning("t_boot", "warn", "one-shot step failed");
assert_eq!(
find("t_boot").map(|w| w.message),
Some("one-shot step failed".to_owned())
);
// A later boot_warning for the same kind still just replaces the
// payload (same registry semantics as `set_warning`).
set_boot_warning("t_boot", "crit", "still failing");
let w = find("t_boot").expect("present");
assert_eq!(w.level, "crit");
assert_eq!(w.message, "still failing");
}
#[test]
fn concurrent_same_kind_resolves_to_absent_after_all_drop() {
// Many threads contend on ONE kind, each holding its own guard