Skip to content

feat(schedule): warn at startup when the agent state allowlist resolves to deny-all - #55

Open
arcuru-bot wants to merge 2 commits into
arcuru:mainfrom
arcuru-bot:fix/agent-state-deny-all-warn
Open

feat(schedule): warn at startup when the agent state allowlist resolves to deny-all#55
arcuru-bot wants to merge 2 commits into
arcuru:mainfrom
arcuru-bot:fix/agent-state-deny-all-warn

Conversation

@arcuru-bot

Copy link
Copy Markdown
Contributor

Two commits, one thread: the agent_state_admin design doc claimed a manifest∩operator allowlist model that never shipped.

The finding. The doc's Implementation Log marked three rows done that do not exist in the tree: resolve_agent_allowlist() (zero hits across crates/), the hub factory build_agent_state_admin (only a stale doc-comment referenced it), and a manifest declaration of the cap on the schedule extension (every builtin extension ships requested_capabilities: Vec::new()). All eight extension/mod.rs intersection tests listed in the doc were never written.

The call. Rather than build the intersection layer, this retracts it as a future refinement: the manifest side has no declarers and nothing enforces it (extensions build their own ScopedAgentStateAdmin from the operator map), so its only live behavior would be a pass-through. The operator's agent_state_allowlist map is the one real scoping input, and the doc now says exactly that.

What ships. The genuinely missing piece the user guide already promises (configuration.md: "logged at WARN on startup"): a one-time deny-all WARN. deny_all_warning() in agent_state.rs builds the message — naming the extension and the config key — and the schedule extension logs it at its construction site (once at startup for a global-scope extension). Two unit tests pin the message shape and the silence of healthy configurations.

Also fixed in passing: the doc's Scoped Wrapper draft showed HashSet<String> with "empty = deny-all", which inverts the shipped Option<HashSet<String>> encoding (None = unrestricted vs Some(empty) = deny-all are distinct meanings); and stale code comments pointing at the never-built factory.

Verification: nix build .#checks.x86_64-linux.{lint,treefmt,test,doc,build} --no-link — all five pass. Targeted: cargo test -p chaz-core --lib agent_state 11/11, extensions::schedule 7/7.

No workflow files touched. Docs: docs/src/design/agent_state_admin.md.

…es to deny-all

A deny-all entry (agent_state_allowlist.<ext>: []) is invisible at the
tool boundary - every lookup fails with the uniform not-found error, so
a broken config looks identical to a working one until someone stares at
'not found' errors. deny_all_warning() in agent_state.rs builds the
operator-facing message (naming the extension and the config key) and
the schedule extension logs it once at its construction site, which for
a global-scope extension is once at startup.

Also repoints the stale in_scope doc comment that referenced a
never-built ExtensionHub::build_agent_state_admin factory, and corrects
the CapabilityRequest::AgentStateAdmin variant docs, which claimed the
operator injects the agents field - nothing injects it today; the live
scoping input is the operator map applied by the extension itself.
…t shipped

The Implementation Log claimed resolve_agent_allowlist() intersection
tests, a hub-side build_agent_state_admin factory, and a manifest
declaration of the cap on the schedule extension - none of which exist.
Grep finds zero hits for the function and the factory, all eight
extension/mod.rs intersection tests were never written, and every
builtin extension ships requested_capabilities: Vec::new().

Rewrite the log, tests table, and status header to match the tree: the
operator's agent_state_allowlist map is the only scoping input, and each
consuming extension builds its own ScopedAgentStateAdmin from its map
entry at instantiate time. The manifest-intersection model stays in the
doc as an explicitly-marked future refinement. Also fix the Scoped
Wrapper code block, whose pre-implementation draft used
HashSet<String> with empty = deny-all - the shipped encoding is
Option<HashSet<String>>, where None means unrestricted and Some(empty)
means deny-all; the draft collapsed those two meanings into one.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant