fix(#2190): replace MANAGER_AGENT fallbacks with "operator" for attribution

- 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 <parent> only
This commit is contained in:
damocles 2026-07-04 18:29:42 +02:00 committed by mara
commit 9b2d16ae6a
6 changed files with 16 additions and 22 deletions

View file

@ -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");

View file

@ -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<Vec<LooseEnd>> {
}
// 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;
}

View file

@ -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}, \

View file

@ -85,7 +85,7 @@ async fn dispatch(req: &HostRequest, coord: Arc<Coordinator>) -> HostResponse {
hive_sh4re::ApprovalKind::Spawn,
"",
None,
hive_sh4re::MANAGER_AGENT,
"operator",
)?;
tracing::info!(%id, %name, "spawn approval queued");
HostResponse::success()

View file

@ -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");