Skip to content

fix(scoped-agent): escalate synthesized scope misses instead of blocking - #262

Open
Ar9av wants to merge 1 commit into
mainfrom
fix/257-scoped-agent-step-up
Open

Ar9av wants to merge 1 commit into
mainfrom
fix/257-scoped-agent-step-up

Conversation

@Ar9av

@Ar9av Ar9av commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Closes #257.

The problem

scoped-agent was the largest single source of blocks on both agent paths measured, and the only measured cause of blocking a legitimate action.

lane total blocks scoped-agent share
path A 21 14 (67%)
path B (enforce) 45 15 (33%)

The benchmark includes a no-injection utility control: the same privileged action requested openly by the user, which a correct system performs. With enforcement on it fell from 100% to 33.3% success — in 2 of 3 repetitions the user's own request did not complete. It was the only over-blocking signal in ~800 trials.

Why

The code treated every scope denial as "explicit operator intent". That holds for a scope an operator authored; it does not for one an LLM predicts from the first prompt. When the prediction omits a tool the request plainly implies, the legitimate call is denied along with the attacks — and the rule cannot distinguish them, because it never inspects the invocation, only the capability.

Production reason string on all 15: [HIGH] [scoped agent] Tool 'Bash' is explicitly denied for this session — where that deny was synthesized, not authored.

What changes

Scopes now carry provenance:

  • synthesize_scoped_rules and the static fallback stamp source: "synthesized"
  • a synthesized miss → MEDIUM / step_up with softFailOpen: a surface that can ask a human does; one that cannot warns and proceeds
  • an operator-authored denial → HIGH / block, unchanged
  • a scope with no source (anything written before this) → keeps hard-blocking

The softer path is opt-in by construction, so this cannot silently weaken existing deployments. Attack-specific rules are untouched and still block on their own merits — what stops is failing closed on a prediction.

scopeSource is also on the finding, so telemetry and the console can finally report capability scoping separately from attack recognition instead of merging two very different claims into one block rate.

Tests

tests/test_scoped_agent_provenance.py, 10 tests: verdict/severity per provenance, threading through check_scoped_rules, legacy scopes keeping strict behaviour, allowed tools still allowed, paused scopes inert, both synthesis paths stamping themselves, and an end-to-end reproduction of the utility-control failure.

Full suite: 24 failed / 1739 passed against a clean-main baseline of 24 failed / 1729 passed — same failures, +10 new tests, no regressions. (The 24 are pre-existing; 4 adapter files excluded in both runs, their namespace packages aren't installed in a bare clone.)

https://claude.ai/code/session_01YU9bdvnpgAc6XyWTAoL12M

`scoped-agent` was the largest single source of blocks on both agent paths
measured (14 of 21, and 15 of 45), and the only measured cause of blocking a
legitimate action: with enforcement on, the no-injection utility control fell
from 100% to 33.3% success — in 2 of 3 repetitions the user's own request did
not complete.

The code treated every scope denial as "explicit operator intent". That is true
for a scope an operator authored, and false for one an LLM predicted from the
first prompt. When the prediction omits a tool the request plainly implies, the
legitimate call is denied along with the attacks, and the rule cannot tell them
apart because it never looks at the invocation — only at the capability.

Scopes now record provenance:

- `synthesize_scoped_rules` and the static fallback stamp `source: synthesized`
- a synthesized miss is MEDIUM/`step_up` with `softFailOpen`, so a surface that
  can ask a human does, and one that cannot warns and proceeds
- operator-authored denials keep hard-blocking, unchanged
- a scope with no `source` (written before this) keeps hard-blocking, so the
  softer path is opt-in rather than a silent weakening

Attack-specific rules are untouched and still block on their own merits; what
stops is failing closed on a prediction.

Closes #257

Claude-Session: https://claude.ai/code/session_01YU9bdvnpgAc6XyWTAoL12M
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.

scoped-agent denials over-block: only measured cause of blocking legitimate actions (utility control 100% -> 33%)

1 participant