c0re: guard the agent-creation path every hive actually uses

The reserved-name check landed only in `swarm-controller::create_agent`.
That daemon is opt-in and off on most hives, so the ordinary per-hive
flow -- `request_init_config` -> `handle_request_init_config` ->
`require_new_child` -> `submit_init_config` -- stayed exactly as
unguarded as before: an agent named `operator`, `forge` or `system` was
still creatable through the path every hive uses, with no warning.

Caught in review by argus. The issue named `create_agent` as the
existing shape to copy, so the shape got copied and the question of
which OTHER sites create an agent never got asked -- an issue naming one
call site is describing an exemplar, not an inventory.

Same treatment as the other path: warn, do not refuse.

The warning needs somewhere to go. `Response` had `Ok` (carries nothing)
and `Err` (refuses), so a check that warns had no way to reach its
caller. Adds `Response::OkWarn { warnings }` -- additive, every existing
`Ok` site is untouched -- rendered by `format_ack` *after* the success
line rather than instead of it: the approval really was queued, and a
warning shown as a failure invites a retry that queues a second one.

Mutation-verified: dropping the warnings and unconditionally appending a
marker each turn a different test red.
This commit is contained in:
atlas 2026-08-27 11:26:26 +02:00 committed by mara
commit 7bb68fe819
3 changed files with 75 additions and 2 deletions

View file

@ -29,8 +29,27 @@ pub(super) fn handle_request_init_config(
return err;
}
tracing::info!(%agent, %name, "request_init_config");
// Warn, do not refuse: an agent already created under a colliding
// name must stay re-initialisable, so the refusal comes later, once
// the warning has had time to be seen.
//
// Checked HERE and not only in `swarm-controller::create_agent`:
// that daemon is opt-in and off on most hives, while this is the
// path the `request_init_config` tool takes on every hive. Guarding
// only the rarer one would have left the common flow exactly as
// unguarded as before.
let warnings = if hive_types::is_reserved_name(name) {
tracing::warn!(%agent, %name, "request_init_config: reserved name");
vec![format!(
"agent name {name:?} is a reserved protocol name — messages from this agent will be \
indistinguishable from hyperhive's own; this will become an error"
)]
} else {
Vec::new()
};
match submit_init_config(coord, name, Some(agent), description) {
Ok(_id) => Response::Ok,
Ok(_id) if warnings.is_empty() => Response::Ok,
Ok(_id) => Response::OkWarn { warnings },
Err(e) => Response::Err {
message: format!("{e:#}"),
},