Problem
Threshold sync implementation is close, but there are semantic gaps that can cause behavior to diverge from configured policy:
cloud_only + fail_open=false is currently bypassed by broad exception fallback in scan flow.
- Per-scan thread-local threshold override is not cleared if detector throws, risking stale override leakage.
- Cloud
project_settings returned by resolve endpoint are fetched but not applied in SDK (with local-explicit-wins semantics).
Expected behavior
cloud_only with fail_open=false must fail closed and raise ThresholdUnavailableError.
- Threshold override must always be cleared, including failure paths.
- SDK should apply cloud
project_settings (confidence_threshold, cleaning_method, on_detect) only when not explicitly set locally.
- Applying cloud cleaning method should invalidate/rebuild cleaner + detector.
- Resolution fetch should not be duplicated when settings + mode are both needed.
Proposed changes
- Narrow exception handling in
AgentShield._scan_single():
- re-raise
ThresholdUnavailableError
- only soft-fallback on transient/non-policy errors
- Wrap detect call in
try/finally and always clear threshold override.
- Add single-fetch flow:
- fetch
cloud_resolution once
- apply cloud settings from
project_settings block
- pass same
cloud_resolution into resolve_with_mode(...)
- Extend
ThresholdManager.resolve_with_mode(...) to accept optional cloud_resolution.
- Remove unrelated
.gitignore change (docs/) from threshold-sync scope.
Acceptance criteria
cloud_only + fail_open=false raises and does not silently fall back.
- No override leakage across scans when detect errors occur.
- Cloud settings are applied only when local explicit values are absent.
- Cleaner/detector rebuild when cloud cleaning method is applied.
- All tests pass.
Tests to add
tests/test_shield.py
- fail-closed test for
cloud_only
- override-clear-on-exception test
- cloud settings applied/not-applied cases
- cleaner/detector invalidation on cloud cleaning method
tests/test_threshold.py
resolve_with_mode(..., cloud_resolution=...) no second fetch
Problem
Threshold sync implementation is close, but there are semantic gaps that can cause behavior to diverge from configured policy:
cloud_only + fail_open=falseis currently bypassed by broad exception fallback in scan flow.project_settingsreturned by resolve endpoint are fetched but not applied in SDK (with local-explicit-wins semantics).Expected behavior
cloud_onlywithfail_open=falsemust fail closed and raiseThresholdUnavailableError.project_settings(confidence_threshold,cleaning_method,on_detect) only when not explicitly set locally.Proposed changes
AgentShield._scan_single():ThresholdUnavailableErrortry/finallyand always clear threshold override.cloud_resolutiononceproject_settingsblockcloud_resolutionintoresolve_with_mode(...)ThresholdManager.resolve_with_mode(...)to accept optionalcloud_resolution..gitignorechange (docs/) from threshold-sync scope.Acceptance criteria
cloud_only + fail_open=falseraises and does not silently fall back.Tests to add
tests/test_shield.pycloud_onlytests/test_threshold.pyresolve_with_mode(..., cloud_resolution=...)no second fetch