hive-c0re: default new agents to root instead of under the bootstrap container
This commit is contained in:
parent
08afa49c96
commit
513c828ab2
2 changed files with 32 additions and 39 deletions
|
|
@ -67,9 +67,11 @@ where system-level facts live.
|
|||
empty map → every agent treated as root (safe degradation for
|
||||
fresh installs that haven't run `meta::sync_agents` yet).
|
||||
2. **Reconcile**: `meta::sync_agents` calls `topology::reconcile`
|
||||
alongside its `flake.nix` regeneration. New agents land at their
|
||||
default position (manager as parent, manager itself as root);
|
||||
removed agents drop. Existing entries are preserved as-is so
|
||||
alongside its `flake.nix` regeneration. New agents default to root
|
||||
(null parent) — an agent-requested sub-agent already carries an
|
||||
explicit requester-as-parent edge from its `init_config` approval, so
|
||||
only user/operator-initiated spawns hit this default, and those are
|
||||
roots; removed agents drop. Existing entries are preserved as-is so
|
||||
operator overrides stick across regenerations. Pending-init agents
|
||||
(an operator-approved proposed config repo but no container yet —
|
||||
`Coordinator::pending_init_names`) are kept too, so the
|
||||
|
|
|
|||
|
|
@ -175,9 +175,12 @@ pub fn write(topology: &BTreeMap<String, Option<String>>) -> std::io::Result<()>
|
|||
std::fs::write(&path, format!("{text}\n"))
|
||||
}
|
||||
|
||||
/// Compute the default topology for a fresh install: every non-manager
|
||||
/// agent has the manager as parent; manager itself is root. Used by
|
||||
/// `meta::sync_agents` on first call to seed `topology.json`.
|
||||
/// Compute the default topology for a fresh install: every agent is a
|
||||
/// root (parent = null). There is no structural "manager" — agents
|
||||
/// arrange themselves via explicit parent edges (an agent-requested
|
||||
/// sub-agent gets a requester-as-parent edge at `init_config`; the
|
||||
/// operator reparents via the dashboard / `RequestSetParent` API).
|
||||
/// Used by `meta::sync_agents` on first call to seed `topology.json`.
|
||||
///
|
||||
/// As soon as an explicit write lands (dashboard / `RequestSetParent`
|
||||
/// API), this seeding stops touching pre-existing entries —
|
||||
|
|
@ -192,14 +195,7 @@ pub fn write(topology: &BTreeMap<String, Option<String>>) -> std::io::Result<()>
|
|||
pub fn default_seed(agent_names: &[String]) -> BTreeMap<String, Option<String>> {
|
||||
let mut out = BTreeMap::new();
|
||||
for name in agent_names {
|
||||
if name == crate::lifecycle::MANAGER_NAME {
|
||||
out.insert(name.clone(), None);
|
||||
} else {
|
||||
out.insert(
|
||||
name.clone(),
|
||||
Some(crate::lifecycle::MANAGER_NAME.to_owned()),
|
||||
);
|
||||
}
|
||||
out.insert(name.clone(), None);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
|
@ -355,12 +351,14 @@ pub fn apply_reconcile(
|
|||
let mut changed = false;
|
||||
for name in agent_names {
|
||||
if !next.contains_key(name) {
|
||||
let parent = if name == crate::lifecycle::MANAGER_NAME {
|
||||
None
|
||||
} else {
|
||||
Some(crate::lifecycle::MANAGER_NAME.to_owned())
|
||||
};
|
||||
next.insert(name.clone(), parent);
|
||||
// A new agent with no declared parent defaults to root
|
||||
// (parent = null). Agent-requested sub-agents always carry an
|
||||
// explicit requester-as-parent edge (written at init_config
|
||||
// approval), so they never hit this default — only
|
||||
// user/operator-initiated spawns do, and those are roots. No
|
||||
// agent is structurally privileged here: "root-ness" is just
|
||||
// a null parent.
|
||||
next.insert(name.clone(), None);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -491,26 +489,19 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn default_seed_makes_manager_root_others_children() {
|
||||
fn default_seed_makes_every_agent_root() {
|
||||
// No structural manager: every agent defaults to root (null
|
||||
// parent). Explicit edges (init_config / dashboard) are layered
|
||||
// on later.
|
||||
let agents = vec![
|
||||
"alice".to_owned(),
|
||||
crate::lifecycle::MANAGER_NAME.to_owned(),
|
||||
"bob".to_owned(),
|
||||
];
|
||||
let seed = default_seed(&agents);
|
||||
assert_eq!(
|
||||
seed.get(crate::lifecycle::MANAGER_NAME),
|
||||
Some(&None),
|
||||
"manager should be root"
|
||||
);
|
||||
assert_eq!(
|
||||
seed.get("alice"),
|
||||
Some(&Some(crate::lifecycle::MANAGER_NAME.to_owned()))
|
||||
);
|
||||
assert_eq!(
|
||||
seed.get("bob"),
|
||||
Some(&Some(crate::lifecycle::MANAGER_NAME.to_owned()))
|
||||
);
|
||||
assert_eq!(seed.get(crate::lifecycle::MANAGER_NAME), Some(&None));
|
||||
assert_eq!(seed.get("alice"), Some(&None));
|
||||
assert_eq!(seed.get("bob"), Some(&None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -665,17 +656,17 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn apply_reconcile_adds_missing_live_agent_under_manager() {
|
||||
fn apply_reconcile_adds_missing_live_agent_as_root() {
|
||||
// A live agent with no prior topology entry defaults to root
|
||||
// (null parent) — no structural manager to hang it under.
|
||||
let live = vec![
|
||||
crate::lifecycle::MANAGER_NAME.to_owned(),
|
||||
"newbie".to_owned(),
|
||||
];
|
||||
let (next, changed) = apply_reconcile(&BTreeMap::new(), &live, &[]);
|
||||
assert!(changed);
|
||||
assert_eq!(
|
||||
next.get("newbie"),
|
||||
Some(&Some(crate::lifecycle::MANAGER_NAME.to_owned()))
|
||||
);
|
||||
assert_eq!(next.get("newbie"), Some(&None));
|
||||
assert_eq!(next.get(crate::lifecycle::MANAGER_NAME), Some(&None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue