topology: drop the parent field and the hierarchy it fed
`topology.json` was a map of `name -> parent | null`, and that value fed the whole agent hierarchy: `<parent>` / `<children>` recipient sentinels, the reparenting API (CLI verb, wire verb, dashboard endpoints, DAG node), the dashboard tree, the rebuild depth sort, and an unconditional bind-mount grant giving every agent RW on its direct children's state. Per the operator's ruling the field goes, and with it all of the above. The file survives as what remains once the value is gone: the roster of agent names, which is the set `ManageRootAgent` grants mounts over. It is now a JSON array; `read` still accepts the old map shape and keeps its keys, so a hive that upgrades across this does not blank its roster (and so no capability holder loses its mounts for the length of that window). Two sites kept their behaviour under a different recipient rather than losing it. Both addressed `<parent>`, which the broker already resolved to `operator` for a root agent, and every agent is now what that fallback called a root: - the harness's turn-failure / plugin-failure notification (`Surface::send_to_parent` -> `send_to_operator`), and - the send allow-list's always-permitted escape hatch, so an agent with a restrictive allow-list still has a way to say it is stuck. What is NOT preserved, deliberately: an agent with no capability no longer sees any other agent's dirs. `ManageRootAgent`'s own grant is unchanged -- still every agent in the roster, still state RW + config RO, still no `harness`. The dashboard's reparenting control (the M0V3 picker) is deleted with its CSS. The tree rendering that reads `ContainerView.parent` is left for the frontend owner -- it degrades to a flat list with the field gone.
This commit is contained in:
parent
392f16cbc0
commit
d94bc2188d
28 changed files with 236 additions and 1513 deletions
|
|
@ -17,23 +17,6 @@ pub const MANAGER_AGENT: &str = "ruth";
|
|||
/// dashboard's inbox view — they are never `recv`'d by an agent harness.
|
||||
pub const OPERATOR_RECIPIENT: &str = "operator";
|
||||
|
||||
/// Reserved magic recipient — `send(to: "<parent>", ...)` is rewritten
|
||||
/// by hive-c0re at delivery time to whoever `topology::parent_of(sender)`
|
||||
/// returns, or to [`OPERATOR_RECIPIENT`] when the sender is a root agent
|
||||
/// (no parent). Lets agents address their parent without hardcoding the
|
||||
/// label, so runtime reparenting requires no agent-side restart. The
|
||||
/// angle brackets are not valid in agent names (validators reject
|
||||
/// `<`/`>`), so this name can never collide with a real recipient.
|
||||
pub const PARENT_RECIPIENT: &str = "<parent>";
|
||||
|
||||
/// Reserved magic recipient — `send(to: "<children>", ...)` fans out to
|
||||
/// every agent whose direct parent (per `topology.json`) is the sender.
|
||||
/// Lets a sub-manager nudge its subtree without enumerating labels at
|
||||
/// call-time; topology changes propagate for free. The angle brackets
|
||||
/// are structurally safe — agent name validation rejects `<`/`>`.
|
||||
/// Delivers to an empty set (no-op) for leaf agents that have no children.
|
||||
pub const CHILDREN_RECIPIENT: &str = "<children>";
|
||||
|
||||
/// Sender hive-c0re uses for events it pushes into the manager's inbox.
|
||||
/// Manager harness recognises this and parses the body as a `HelperEvent`.
|
||||
pub const SYSTEM_SENDER: &str = "system";
|
||||
|
|
@ -113,9 +96,7 @@ pub struct SchedulePromptPayload {
|
|||
|
||||
#[cfg(test)]
|
||||
mod reserved_name_tests {
|
||||
use super::{
|
||||
CHILDREN_RECIPIENT, MANAGER_AGENT, OPERATOR_RECIPIENT, PARENT_RECIPIENT, SYSTEM_SENDER,
|
||||
};
|
||||
use super::{MANAGER_AGENT, OPERATOR_RECIPIENT, SYSTEM_SENDER};
|
||||
use hive_types::{Ident, RESERVED_NAMES_ENV, is_reserved_name};
|
||||
|
||||
/// The blacklist as nix rendered it for this test run.
|
||||
|
|
@ -182,24 +163,6 @@ mod reserved_name_tests {
|
|||
}
|
||||
}
|
||||
|
||||
/// The other half, and the reason the test above is not vacuous: these
|
||||
/// sentinels are *unreachable* as agent names because the charset
|
||||
/// rejects them, so they are correctly absent from the list. If a
|
||||
/// charset change ever made one parseable, it would become a real
|
||||
/// collision and this test is what notices.
|
||||
#[test]
|
||||
fn bracketed_recipients_cannot_be_agent_names() {
|
||||
let owned = reserved();
|
||||
let reserved: Vec<&str> = owned.iter().map(String::as_str).collect();
|
||||
for sentinel in [PARENT_RECIPIENT, CHILDREN_RECIPIENT] {
|
||||
assert!(
|
||||
Ident::parse(sentinel).is_err(),
|
||||
"{sentinel:?} parses as an ident now — it is reachable as an agent name and must be reserved"
|
||||
);
|
||||
assert!(!is_reserved_name(sentinel, &reserved));
|
||||
}
|
||||
}
|
||||
|
||||
/// `ruth` is a real agent, not a protocol literal, so it is not
|
||||
/// reserved: a second agent wanting the name is a *taken* name, which
|
||||
/// the roster check answers. Recorded as a test so the distinction is
|
||||
|
|
|
|||
Loading…
Reference in a new issue