hive-ag3nt: scrub mcp.rs cookies (#716 batch 8)

Last #716 hotspot — scrub-only batch. All substantive prose is
already documented in docs/turn-loop.md::MCP surface (Sub-agent
tools, Manager tools, Tool whitelist, Tool envelope), so the 10
cookies in mcp.rs come out without prose extraction.

- format_agent_meta rustdoc: drop #432 attribution, add docs pointer
  for the running=false / status_text-stale rationale
- get_agent_meta hive/swarm comment: drop #710 attribution
- AgentServer + ManagerServer add-tool warnings: drop #511 attribution
  twice (kept the lockstep invariant)
- edit_schedule description: drop #474 + #478 cookies in user-facing
  tool text
- cancel_loose_end description: drop #250 cookie in user-facing text
- Manager allow-list block: drop the long #444/#235/#467/#472/#474/
  #478/#509 attribution roll, keep the lockstep invariant
- check_send_allowed (<parent> branch): drop #692, replace with the
  actual semantics ("falls back to operator for root agents")
- prompts/system.md: drop #474 cookie from edit_schedule line
- Cargo.toml [[bin]]: drop #598 pre-/post- split history, add docs
  pointer to docs/turn-loop.md::Harness binary shape

cargo check + 56 tests pass.
Closes #716 (last cookie hotspot).
This commit is contained in:
iris 2026-05-31 17:37:33 +02:00 committed by mara
commit 2a2d76d733
3 changed files with 25 additions and 27 deletions

View file

@ -295,9 +295,10 @@ fn loose_end_kind_label(kind: hive_sh4re::CancelLooseEndKind) -> &'static str {
/// `hyperhive_rev`, and `running` are always shown; `status` only
/// appears when one is set, otherwise the line reads `status: <none>`.
/// When `running` is false the host has already cleared `status_text`
/// (it would be stale from before the stop, #432) so the status line
/// is implicitly `<none>` in that case — but the explicit `running:
/// no` line tells the caller WHY.
/// (it would be a stale snapshot from before the stop) so the status
/// line is implicitly `<none>` in that case — but the explicit
/// `running: no` line tells the caller WHY. See
/// `docs/turn-loop.md::Sub-agent tools` (`get_agent_meta`).
#[must_use]
pub fn format_agent_meta(resp: Result<SocketReply, anyhow::Error>) -> String {
match resp {
@ -315,8 +316,8 @@ pub fn format_agent_meta(resp: Result<SocketReply, anyhow::Error>) -> String {
let run = if running { "yes" } else { "no" };
let mut out =
format!("name: {name}\nrole: {role}\nhyperhive_rev: {rev}\nrunning: {run}");
// #710: surface hive + swarm display names only when set,
// so single-hive deployments don't see noisy `<none>` lines.
// Surface hive + swarm display names only when set, so
// single-hive deployments don't see noisy `<none>` lines.
if let Some(hn) = hive_name.as_deref() {
use std::fmt::Write as _;
let _ = write!(out, "\nhive_name: {hn}");
@ -507,8 +508,7 @@ impl AgentServer {
// its name to `allowed_mcp_tools(Flavor::Agent)` below. Claude
// Code's permission gate refuses uninlisted MCP tools in
// non-interactive `--print` mode with "permissions not granted yet"
// — same failure mode #511 cleaned up on the manager side. Keep the
// two lists in lockstep.
// — keep the two lists in lockstep.
#[tool_router]
impl AgentServer {
#[tool(
@ -1102,8 +1102,7 @@ impl ManagerServer {
// its name to `allowed_mcp_tools(Flavor::Manager)` below. Claude
// Code's permission gate refuses uninlisted MCP tools in
// non-interactive `--print` mode with "permissions not granted yet"
// — exactly the failure mode PR #511 cleaned up. Keep the two lists
// in lockstep.
// — keep the two lists in lockstep.
#[tool_router]
impl ManagerServer {
#[tool(
@ -1387,11 +1386,11 @@ impl ManagerServer {
}
#[tool(
description = "Edit an existing scheduled prompt's mutable fields (#474). Pass only \
description = "Edit an existing scheduled prompt's mutable fields. Pass only \
the fields you want to change anything omitted keeps its current value. Editable: \
`body`, `description`, `interval_seconds` (positive only via this tool; flipping \
recurringone-shot is operator-only via the dashboard), `next_fire_at_unix`, and \
the target set via `targets_add` / `targets_remove` (#478). Both target lists are \
the target set via `targets_add` / `targets_remove`. Both target lists are \
applied in the same transaction with removes-before-adds, so a single edit can \
swap a target atomically. Re-adding a previously-removed target starts a fresh \
per-target history (drops the tombstone). Draining all targets auto-cancels the \
@ -1659,7 +1658,7 @@ impl ManagerServer {
with the operator-override sentinel so the asker unblocks), a `reminder` \
(hard-deleted before fire), or an `approval` (withdraws a pending approval \
you submitted; the dashboard pulls the card from pending and the row resolves \
as `cancelled` instead of approved/denied/failed closes #250). `kind` is \
as `cancelled` instead of approved/denied/failed). `kind` is \
`\"question\"`, `\"reminder\"`, or `\"approval\"`; `id` is the row id from \
`get_loose_ends` or the original submission reply. Manager surface bypasses \
the owner check on the sub-agent flavour use for hive-wide cleanup of \
@ -1795,13 +1794,12 @@ pub fn allowed_mcp_tools(flavor: Flavor) -> Vec<String> {
"restart",
"update",
"request_apply_commit",
// Tools added post-#444 / #235 / #467 / #472 / #474 / #478 that
// got missed in the allow-list when their `#[tool]` impls
// landed. Claude Code's permission gate refuses uninlisted
// tools in non-interactive `--print` mode with a "permissions
// not granted yet" error (hm1nd hit this trying to run the
// dedup pass for #509). Keep this block in lockstep with the
// `#[tool]` fns in the `ManagerServer` impl.
// The remaining manager tools below were added incrementally
// and have historically been missed in the allow-list when
// their `#[tool]` impls landed. Claude Code's permission gate
// refuses uninlisted tools in non-interactive `--print` mode
// with a "permissions not granted yet" error — keep this
// block in lockstep with the `#[tool]` fns in `ManagerServer`.
"request_update_meta_inputs",
"request_schedule_prompt",
"fire_schedule_now",
@ -1912,7 +1910,8 @@ fn check_send_allowed(to: &str) -> Result<(), String> {
// can rewire who the parent IS via `set_parent` without
// having to remember to update the per-agent allow-list.
// The broker resolves the sentinel to the real parent label
// on the host side per topology.json (#692).
// on the host side per topology.json (falls back to `operator`
// for root agents).
return Ok(());
}
let Ok(raw) = std::fs::read_to_string(SEND_ALLOW_PATH) else {