From 9b2d16ae6a8e4c78d2d255d596ab3b7f1008ad8d Mon Sep 17 00:00:00 2001 From: damocles Date: Sat, 4 Jul 2026 18:29:42 +0200 Subject: [PATCH] fix(#2190): replace MANAGER_AGENT fallbacks with "operator" for attribution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - loose_ends.rs: NULL submitter on legacy approval rows → "operator" - questions.rs: NULL submitter on cancel_loose_end → "operator" - server.rs: HostRequest::RequestSpawn submitter → "operator" - dashboard.rs: web-UI spawn submitter → "operator" - socket_server.rs: submit_init_config with no declared parent → "operator" - mcp.rs: drop MANAGER_AGENT exception from check_send_allowed; keep only --- hive-ag3nt/src/mcp.rs | 19 ++++++------------- hive-c0re/src/dashboard.rs | 2 +- hive-c0re/src/loose_ends.rs | 6 +++--- hive-c0re/src/questions.rs | 5 +++-- hive-c0re/src/server.rs | 2 +- hive-c0re/src/socket_server.rs | 4 ++-- 6 files changed, 16 insertions(+), 22 deletions(-) diff --git a/hive-ag3nt/src/mcp.rs b/hive-ag3nt/src/mcp.rs index fc78cf90..95af42f2 100644 --- a/hive-ag3nt/src/mcp.rs +++ b/hive-ag3nt/src/mcp.rs @@ -2182,21 +2182,14 @@ const EXTRA_MCP_PATH: &str = "/etc/hyperhive/extra-mcp.json"; const SEND_ALLOW_PATH: &str = "/etc/hyperhive/send-allow.json"; /// Enforce the per-agent send allow-list. Returns `Ok` when the -/// recipient is permitted (no list configured, manager always -/// allowed, or `to` is in the list); returns `Err(refusal)` with a -/// claude-readable string when blocked — the harness surfaces the -/// refusal as the tool result so claude knows the message didn't -/// land and can react (e.g. route via the manager instead). +/// recipient is permitted (no list configured, `` sentinel +/// always allowed, or `to` is in the list); returns `Err(refusal)` +/// with a claude-readable string when blocked ��� the harness surfaces +/// the refusal as the tool result so claude knows the message didn't +/// land and can react (e.g. route via `` instead). fn check_send_allowed(to: &str) -> Result<(), String> { - if to == hive_sh4re::MANAGER_AGENT { - // Always allow agents to talk to the manager — otherwise a - // misconfigured allow-list could leave a sub-agent unable - // to ask for help. - return Ok(()); - } if to == hive_sh4re::PARENT_RECIPIENT { - // Always allow `` — same escape-hatch rationale as - // the manager exception. The allow-list constrains peer + // Always allow `` — the allow-list constrains peer // chatter, not the structural reporting line; the operator // can rewire who the parent IS via `set_parent` without // having to remember to update the per-agent allow-list. diff --git a/hive-c0re/src/dashboard.rs b/hive-c0re/src/dashboard.rs index 74353bc8..d4789852 100644 --- a/hive-c0re/src/dashboard.rs +++ b/hive-c0re/src/dashboard.rs @@ -1681,7 +1681,7 @@ async fn post_request_spawn( hive_sh4re::ApprovalKind::Spawn, "", None, - hive_sh4re::MANAGER_AGENT, + "operator", ) { Ok(id) => { tracing::info!(%id, %name, "operator: spawn approval queued via dashboard"); diff --git a/hive-c0re/src/loose_ends.rs b/hive-c0re/src/loose_ends.rs index 46f7e597..bdecc232 100644 --- a/hive-c0re/src/loose_ends.rs +++ b/hive-c0re/src/loose_ends.rs @@ -16,7 +16,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use anyhow::Result; -use hive_sh4re::{LooseEnd, MANAGER_AGENT}; +use hive_sh4re::LooseEnd; use crate::coordinator::Coordinator; @@ -56,12 +56,12 @@ pub fn for_agent(coord: &Coordinator, agent: &str) -> Result> { } // Show each pending approval to the agent that submitted it. The // submitter column is NULL for rows predating it; those count as - // the root agent's. + // operator-initiated (no agent tracking predates the column). for a in coord.approvals.pending()? { let submitter = coord .approvals .submitter_of(a.id)? - .unwrap_or_else(|| MANAGER_AGENT.to_owned()); + .unwrap_or_else(|| "operator".to_owned()); if submitter != agent { continue; } diff --git a/hive-c0re/src/questions.rs b/hive-c0re/src/questions.rs index 2d99dfd8..ca388839 100644 --- a/hive-c0re/src/questions.rs +++ b/hive-c0re/src/questions.rs @@ -203,13 +203,14 @@ pub fn handle_cancel_loose_end( // may withdraw it. Without the ownership check, any // approvals-group agent could cancel any other's approval by // id. A NULL submitter (legacy row predating the column) is - // owned by the root agent. + // treated as operator-initiated (no agent tracking predates + // the column). check_can_cancel_approval(canceller)?; let submitter = coord .approvals .submitter_of(id) .map_err(|e| format!("{e:#}"))? - .unwrap_or_else(|| hive_sh4re::MANAGER_AGENT.to_owned()); + .unwrap_or_else(|| "operator".to_owned()); if submitter != canceller { return Err(format!( "cancel_loose_end: approval {id} was submitted by {submitter}, \ diff --git a/hive-c0re/src/server.rs b/hive-c0re/src/server.rs index a2c63a82..a711bf6b 100644 --- a/hive-c0re/src/server.rs +++ b/hive-c0re/src/server.rs @@ -85,7 +85,7 @@ async fn dispatch(req: &HostRequest, coord: Arc) -> HostResponse { hive_sh4re::ApprovalKind::Spawn, "", None, - hive_sh4re::MANAGER_AGENT, + "operator", )?; tracing::info!(%id, %name, "spawn approval queued"); HostResponse::success() diff --git a/hive-c0re/src/socket_server.rs b/hive-c0re/src/socket_server.rs index 1d5f2d44..a839f86c 100644 --- a/hive-c0re/src/socket_server.rs +++ b/hive-c0re/src/socket_server.rs @@ -1847,8 +1847,8 @@ pub(crate) fn submit_init_config( description.as_deref(), // `parent` is the requesting agent (becomes the new child's // parent); it's also the submitter the approval events route - // back to. No declared parent = operator/root path. - parent.unwrap_or(hive_sh4re::MANAGER_AGENT), + // back to. No declared parent = operator-initiated path. + parent.unwrap_or("operator"), ) .map_err(|e| anyhow::anyhow!("queue approval row: {e:#}"))?; tracing::info!(%id, %name, "init_config approval queued");