hive-c0re: scope list_schedules to what the requester can actually act on

handle_list_schedules took no requester and returned every schedule
unfiltered, unlike cancel_schedule/edit_schedule/fire_schedule_now
which all gate on the shared ownership predicate (self, operator, or
subtree via topology::is_descendant_of). list_schedules now filters
through the same predicate, renamed cancel_authorized ->
schedule_authorized since it backs all four verbs now, not just
cancel.

Fixed five stale 'every schedule' / 'unfiltered' claims found while in
here: filter_ghost_schedule_targets's doc comment, the list_schedules
MCP tool description, docs/tools/scheduling.md's per-verb section
(already self-contradicting its own top-of-file subtree-scoping claim
before this fix), and hive-core-agent-sock's ListSchedules/Schedules
wire-type doc comments (including a stale '(privileged)' marker from
the pre-topology-subtree model).

Credit to atlas: independently found the same fix while finishing
PR #4233 (which documents this bug per mara's 'fix it, don't document
it' ruling) and caught two stale doc spots I'd missed
(hive-core-agent-sock's comments) plus proposed the
schedule_authorized rename. Compared diffs directly before either of
us pushed; he dropped his scheduling.rs changes so we didn't collide.

fixes #4237
This commit is contained in:
damocles 2026-09-11 17:25:45 +02:00 committed by mara
commit 79c43a15d8
5 changed files with 75 additions and 31 deletions

View file

@ -977,11 +977,12 @@ impl AgentServer {
}
#[tool(
description = "List every scheduled prompt in the queue (active + cancelled but \
not yet reaped). Returns the full snapshot schedule id, owner, body, target set \
with per-target last_fired_at + last_result, next fire time, recurring interval. \
description = "List the scheduled prompts you're authorized to see — your own, plus \
any owned by a sub-agent in your subtree (everything, for the operator) active and \
cancelled-but-not-yet-reaped. Returns schedule id, owner, body, target set with \
per-target last_fired_at + last_result, next fire time, recurring interval. \
Use this to look up an id before calling `cancel_schedule`, or to audit what \
the swarm is going to be woken up about next."
your subtree is going to be woken up about next."
)]
async fn list_schedules(&self) -> String {
run_tool_envelope("list_schedules", String::new(), async move {