test(safety): add Phase E comprehensive safety tests

- Add tests for models: ActionMetadata, ActionRequest, ActionResult,
  ValidationRule, BudgetStatus, RateLimitConfig, ApprovalRequest/Response,
  Checkpoint, RollbackResult, AuditEvent, SafetyPolicy, GuardianResult
- Add tests for validation: ActionValidator rules, priorities, patterns,
  bypass mode, batch validation, rule creation helpers
- Add tests for loops: LoopDetector exact/semantic/oscillation detection,
  LoopBreaker throttle/backoff, history management
- Add tests for content filter: PII filtering (email, phone, SSN, credit card),
  secret blocking (API keys, GitHub tokens, private keys), custom patterns,
  scan without filtering, dict filtering
- Add tests for emergency controls: state management, pause/resume/reset,
  scoped emergency stops, callbacks, EmergencyTrigger events
- Fix exception kwargs in content filter and emergency controls to match
  exception class signatures

All 108 tests passing with lint and type checks clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-03 11:52:35 +01:00
parent f36bfb3781
commit 015f2de6c6
8 changed files with 1932 additions and 5 deletions

View File

@@ -370,8 +370,8 @@ class ContentFilter:
if raise_on_block:
raise ContentFilterError(
block_reason or "Content blocked",
detected_category=all_matches[0].category.value if all_matches else "unknown",
pattern_name=all_matches[0].pattern_name if all_matches else None,
filter_type=all_matches[0].category.value if all_matches else "unknown",
detected_patterns=[m.pattern_name for m in all_matches] if all_matches else [],
)
elif all_matches:
logger.debug(

View File

@@ -328,7 +328,7 @@ class EmergencyControls:
if raise_if_blocked:
raise EmergencyStopError(
f"Global emergency state: {self._global_state.value}",
stop_reason=self._get_last_reason("global"),
stop_type=self._get_last_reason("global") or "emergency",
triggered_by=self._get_last_triggered_by("global"),
)
return False
@@ -340,9 +340,9 @@ class EmergencyControls:
if raise_if_blocked:
raise EmergencyStopError(
f"Emergency state for {scope}: {state.value}",
stop_reason=self._get_last_reason(scope),
stop_type=self._get_last_reason(scope) or "emergency",
triggered_by=self._get_last_triggered_by(scope),
scope=scope,
details={"scope": scope},
)
return False