fix(serve): wire per-session capability scopes, skill/memory tools, and policy fail-closed#6140
Merged
Merged
Conversation
bug-ops
force-pushed
the
fix/6045-serve-scope-denials-sentinel
branch
from
July 12, 2026 15:04
60bcdfa to
a202fd1
Compare
bug-ops
enabled auto-merge (squash)
July 12, 2026 15:04
…nd policy fail-closed ScopedToolExecutor now wraps fresh per session instead of being built once and shared, so OutOfScope capability-scope denials reach that session's TrajectorySentinel signal queue like ACP and daemon already do. Startup validation and the per-session wrap now share a single compose_session_tool_tree helper covering the same tool surface, closing a false-positive startup abort for scopes that reference skill_loader/invoke_skill/memory/overflow tools. Those four tool executors are also now wired into /sessions* agents, matching the CLI/TUI/ACP/daemon tool surface (MCP tools, the scheduler executor, and hot-reload broadcast forwarding remain a separately tracked gap). A [tools.policy]/[tools.authorization] compile failure now aborts serve-sessions startup instead of silently disabling policy enforcement, since serve is HTTP-facing with potentially remote/less-trusted callers. CLI/TUI/ACP/daemon keep their existing fail-open behavior unchanged. Closes #6045 Closes #6046 Closes #6008
…eature bundles PolicyGatePieces::policy_configured (#6008) is only read from src/serve/deps.rs, which is gated behind #[cfg(feature = "session")]. Feature bundles that don't pull in session (ide, chat, bench) never compile that reader, so the field was flagged dead_code there, and CI's per-bundle Bundle Check/MSRV jobs deny warnings — failing the build. desktop/server both pull in session transitively, which is why the combined local check suite never caught this.
bug-ops
force-pushed
the
fix/6045-serve-scope-denials-sentinel
branch
from
July 12, 2026 15:27
54f8e64 to
5596822
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes three follow-up gaps in Zeph's
src/serve/*subsystem (/sessions*HTTP+SSE API), all identified during adversarial critic review of recent PRs (#5951/#5958/#5975, #5973/#5977/#5886):ScopedToolExecutor([security.capability_scopes]) was built once, eagerly, and shared across every concurrent/sessions*agent, so it never received a per-session signal-queue wire-up —OutOfScopecapability-scope denials never reached that session'sTrajectorySentinelrisk-escalation tracking, unlike ACP and daemon. It is now wrapped fresh per session, mirroring ACP's per-connection wiring order./sessions*agents never hadskill_loader,invoke_skill(SkillInvokeExecutor),memory, oroverflowtool executors wired in at all, unlike CLI/TUI/ACP/daemon. These are now composed into serve's per-session tool chain, inside the existing trust/policy/adversarial gate stack.[tools.policy]/[tools.authorization]compile failure silently fell back to disabled policy enforcement for serve too (the same fail-open CLI/ACP/daemon intentionally keep) — but serve is an HTTP-facing entrypoint with potentially remote/less-trusted callers who have no visibility into an operator-console-onlytracing::error!line. Serve now aborts startup fail-closed on a real compile failure while staying fail-open when[tools.policy]is legitimately unconfigured.A follow-up finding from the adversarial critic (startup capability-scope validation compiling against a different, narrower tool registry than the per-session wrap — a default-config-reachable false-positive startup abort) was fixed in the same PR by unifying both call sites through one
compose_session_tool_treehelper, so the two registries can no longer drift apart.Closes #6045
Closes #6046
Closes #6008
Test plan
cargo +nightly fmt --checkcargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warningscargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins— 13081/13081 passedRUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links") — clean.local/testing/playbooks/serve.mdand.local/testing/coverage-status.mdupdated with live-testing scenarios for all three fixes