Files
cleveragents-core/features/autonomy_guardrails.feature
CoreRasurae 53455275ba
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 17s
CI / quality (pull_request) Successful in 18s
CI / lint (pull_request) Successful in 23s
CI / security (pull_request) Successful in 31s
CI / typecheck (pull_request) Successful in 35s
CI / integration_tests (pull_request) Successful in 3m46s
CI / unit_tests (pull_request) Successful in 11m44s
CI / docker (pull_request) Successful in 38s
CI / benchmark-regression (pull_request) Successful in 27m39s
CI / coverage (pull_request) Successful in 55m41s
CI / build (push) Successful in 15s
CI / quality (push) Successful in 16s
CI / lint (push) Successful in 19s
CI / typecheck (push) Successful in 32s
CI / benchmark-regression (push) Has been skipped
CI / security (push) Successful in 41s
CI / integration_tests (push) Successful in 2m55s
CI / unit_tests (push) Successful in 11m43s
CI / docker (push) Successful in 40s
CI / benchmark-publish (push) Successful in 16m11s
CI / coverage (push) Successful in 44m49s
feat(automation): add autonomy guardrails and audit trail
Add runtime autonomy constraints (max steps, tool budget, required
confirmations) and a structured audit trail for plan execution.

New domain models:
- AutonomyGuardrails: enforces step limits, tool budgets, and
  confirmation gates with validators and check methods
- GuardrailAuditEntry: records each enforcement event with timestamp,
  event type, guard name, result, reason, and context
- GuardrailAuditTrail: ordered collection of audit entries persisted
  to plan metadata

New service:
- AutonomyGuardrailService: high-level service for configuring
  guardrails per plan, checking constraints, recording audit entries,
  and serializing/restoring state via plan metadata

Tests:
- Behave: 69 scenarios covering model validation, step/budget/
  confirmation checks, audit trail recording, and service operations
- Robot: 8 test cases for autonomy guardrail CLI flag smoke testing
- ASV: 6 benchmark suites measuring enforcement overhead

Documentation:
- Updated docs/reference/automation_profiles.md with guardrail fields,
  enforcement behavior, audit trail schema, and event type reference

ISSUES CLOSED: #204
2026-02-28 22:06:57 +00:00

402 lines
17 KiB
Gherkin

Feature: Autonomy Guardrails and Audit Trail
As a plan executor
I want autonomy guardrails to enforce step limits, tool budgets, and confirmations
So that plan execution stays within defined safety boundaries with a full audit trail
# ---- AutonomyGuardrails model validation ----
Scenario: Create guardrails with all fields
When I create autonomy guardrails with max_steps 10 and tool_budget 50.0
Then the guardrails should have max_steps 10
And the guardrails should have tool_budget 50.0
And the guardrails step_count should be 0
And the guardrails budget_spent should be 0.0
Scenario: Create guardrails with defaults
When I create autonomy guardrails with defaults
Then the guardrails should have max_steps None
And the guardrails should have tool_budget None
And the guardrails should have empty required_confirmations
Scenario: Guardrails reject negative max_steps
When I try to create guardrails with max_steps 0
Then a guardrails validation error should be raised
And the guardrails error should mention "max_steps"
Scenario: Guardrails reject negative tool_budget
When I try to create guardrails with tool_budget -1.0
Then a guardrails validation error should be raised
And the guardrails error should mention "tool_budget"
# ---- Step limit checks ----
Scenario: Step limit allows within bounds
Given guardrails with max_steps 5
When I check step limit at step 3
Then the step check should be allowed
Scenario: Step limit blocks at max
Given guardrails with max_steps 5
When I check step limit at step 5
Then the step check should be denied
Scenario: Step limit blocks above max
Given guardrails with max_steps 3
When I check step limit at step 10
Then the step check should be denied
Scenario: Unlimited steps always allowed
Given guardrails with no step limit
When I check step limit at step 1000
Then the step check should be allowed
# ---- Tool budget checks ----
Scenario: Budget allows within limit
Given guardrails with tool_budget 100.0
When I check tool budget for cost 50.0
Then the budget check should be allowed
Scenario: Budget blocks when exceeded
Given guardrails with tool_budget 10.0 and budget_spent 8.0
When I check tool budget for cost 5.0
Then the budget check should be denied
Scenario: Budget allows exact remaining
Given guardrails with tool_budget 10.0 and budget_spent 5.0
When I check tool budget for cost 5.0
Then the budget check should be allowed
Scenario: Unlimited budget always allowed
Given guardrails with no budget limit
When I check tool budget for cost 999.0
Then the budget check should be allowed
Scenario: Budget rejects negative tool cost
Given guardrails with tool_budget 100.0
When I try to check tool budget for cost -1.0
Then a guardrails validation error should be raised
# ---- Confirmation checks ----
Scenario: Confirmation required for listed operation
Given guardrails with required confirmations "deploy,delete"
When I check confirmation for operation "deploy"
Then confirmation should be required
Scenario: Confirmation not required for unlisted operation
Given guardrails with required confirmations "deploy,delete"
When I check confirmation for operation "read"
Then confirmation should not be required
Scenario: No confirmations required when list empty
Given guardrails with no required confirmations
When I check confirmation for operation "deploy"
Then confirmation should not be required
# ---- Step counter and budget tracking ----
Scenario: Increment step counter
Given guardrails with max_steps 10
When I increment the step counter 3 times
Then the step_count should be 3
Scenario: Record tool cost
Given guardrails with tool_budget 100.0
When I record a tool cost of 25.0
And I record a tool cost of 15.0
Then the budget_spent should be 40.0
Scenario: Record cost rejects negative cost
Given guardrails with tool_budget 100.0
When I try to record a negative cost
Then a guardrails validation error should be raised
# ---- Audit trail ----
Scenario: Audit trail records entries
Given an empty audit trail
When I add a step_allowed entry to the audit trail
And I add a budget_blocked entry to the audit trail
Then the audit trail should have 2 entries
And the audit trail allowed_count should be 1
And the audit trail denied_count should be 1
Scenario: Audit entry has correct fields
When I create an audit entry with event_type step_blocked and guard_name step_limit
Then the audit entry event_type should be "step_blocked"
And the audit entry guard_name should be "step_limit"
And the audit entry result should be "denied"
And the audit entry should have a timestamp
# ---- AutonomyGuardrailService ----
Scenario: Service configures and retrieves guardrails
Given an autonomy guardrail service
When I configure guardrails for plan "plan-001" with max_steps 5
Then the service should return guardrails for plan "plan-001"
And the service guardrails should have max_steps 5
Scenario: Service returns None for unconfigured plan
Given an autonomy guardrail service
Then the service should return None for plan "nonexistent"
Scenario: Service step limit check records audit trail
Given an autonomy guardrail service with guardrails for plan "plan-002"
When I check step limit via service for plan "plan-002" at step 3
Then the audit trail for plan "plan-002" should have 1 entry
Scenario: Service budget check records cost and audit trail
Given an autonomy guardrail service with budget guardrails for plan "plan-003"
When I check tool budget via service for plan "plan-003" with cost 5.0
Then the audit trail for plan "plan-003" should have 1 entry
And the service guardrails budget_spent should be 5.0
Scenario: Service confirmation check records audit trail
Given an autonomy guardrail service with confirmation guardrails for plan "plan-004"
When I check confirmation via service for plan "plan-004" operation "deploy"
Then the audit trail for plan "plan-004" should have 1 entry
Scenario: Service serializes audit trail to metadata
Given an autonomy guardrail service with guardrails for plan "plan-005"
When I check step limit via service for plan "plan-005" at step 1
Then the metadata for plan "plan-005" should contain the audit trail
Scenario: Service loads guardrails from metadata
Given an autonomy guardrail service
When I load guardrails from metadata for plan "plan-006"
Then the service should return guardrails for plan "plan-006"
Scenario: Service removes plan guardrails
Given an autonomy guardrail service with guardrails for plan "plan-007"
When I remove plan "plan-007" from the service
Then the service should return None for plan "plan-007"
Scenario: Service check_step_limit returns True for unconfigured plan
Given an autonomy guardrail service
When I check step limit via service for plan "unknown" at step 100
Then the step limit check should return True
Scenario: Service check_tool_budget returns True for unconfigured plan
Given an autonomy guardrail service
When I check tool budget via service for plan "unknown" with cost 999.0
Then the tool budget check should return True
Scenario: Service check_confirmation returns False for unconfigured plan
Given an autonomy guardrail service
When I check confirmation via service for plan "unknown" operation "deploy"
Then the confirmation check should return False
Scenario: Service configure_guardrails rejects empty plan_id
Given an autonomy guardrail service
When I try to configure guardrails with empty plan_id
Then a guardrails validation error should be raised
Scenario: GuardrailEventType enumerates all event types
Then GuardrailEventType should have at least 10 members
Scenario: GuardrailResult enumerates allowed and denied
Then GuardrailResult should have exactly 2 members
# ---- Wall-clock time checks ----
Scenario: Wall-clock allows when no limit set
Given guardrails with no wall-clock limit
When I check wall-clock time
Then the wall-clock check should be allowed
Scenario: Wall-clock allows when within limit
Given guardrails with wall-clock limit 60.0 seconds started recently
When I check wall-clock time
Then the wall-clock check should be allowed
Scenario: Wall-clock blocks when expired
Given guardrails with wall-clock limit that has already expired
When I check wall-clock time
Then the wall-clock check should be denied
Scenario: Service wall-clock check records audit trail
Given an autonomy guardrail service with wall-clock guardrails for plan "plan-wc"
When I check wall-clock via service for plan "plan-wc"
Then the audit trail for plan "plan-wc" should have 1 entry
# ---- Actor tool-call limits ----
Scenario: Actor tool-call limit allows within bounds
Given guardrails with actor tool-call limit 5
When I check actor tool calls with 3 current calls
Then the actor tool-call check should be allowed
Scenario: Actor tool-call limit blocks at max
Given guardrails with actor tool-call limit 5
When I check actor tool calls with 5 current calls
Then the actor tool-call check should be denied
Scenario: Actor tool-call limit unlimited
Given guardrails with no actor tool-call limit
When I check actor tool calls with 1000 current calls
Then the actor tool-call check should be allowed
Scenario: Service actor tool-call check records audit trail
Given an autonomy guardrail service with actor-limit guardrails for plan "plan-al"
When I check actor tool calls via service for plan "plan-al" with 3 calls
Then the audit trail for plan "plan-al" should have 1 entry
# ---- Bounded audit trail eviction ----
Scenario: Audit trail evicts oldest entry when full
Given an audit trail with max_entries 3
When I add 4 step_allowed entries to the audit trail
Then the audit trail should have 3 entries
And the audit trail allowed_count should be 3
# ---- Edge cases ----
Scenario: Budget blocks when tool_budget is zero
Given guardrails with tool_budget 0.0
When I check tool budget for cost 0.01
Then the budget check should be denied
Scenario: Budget allows zero cost when tool_budget is zero
Given guardrails with tool_budget 0.0
When I check tool budget for cost 0
Then the budget check should be allowed
Scenario: Case-insensitive confirmation matching
Given guardrails with required confirmations "Deploy,DELETE"
When I check confirmation for operation "deploy"
Then confirmation should be required
Scenario: Case-insensitive confirmation matching uppercase query
Given guardrails with required confirmations "deploy"
When I check confirmation for operation "DEPLOY"
Then confirmation should be required
Scenario: Service rejects oversized metadata entries
Given an autonomy guardrail service
When I try to load metadata with oversized audit trail for plan "plan-big"
Then a guardrails validation error should be raised
Scenario: Service rejects oversized confirmations in metadata
Given an autonomy guardrail service
When I try to load metadata with oversized confirmations for plan "plan-big2"
Then a guardrails validation error should be raised
Scenario: Metadata round-trip preserves guardrail state
Given an autonomy guardrail service with guardrails for plan "plan-rt"
When I check step limit via service for plan "plan-rt" at step 3
And I serialize and restore metadata for plan "plan-rt"
Then the restored guardrails for plan "plan-rt" should match the original
# ---- start_time validation ----
Scenario: start_time accepts valid ISO-8601 timestamp
When I create guardrails with a valid start_time
Then the guardrails start_time should be set
Scenario: start_time rejects malformed string
When I try to create guardrails with start_time "not-a-date"
Then a guardrails validation error should be raised
And the guardrails error should mention "start_time"
Scenario: start_time accepts None
When I create autonomy guardrails with defaults
Then the guardrails start_time should be None
Scenario: check_wall_clock handles malformed start_time gracefully
Given guardrails with a malformed start_time bypassing validation
When I check wall-clock time
Then the wall-clock check should be denied
# ---- Retry-per-failure checks ----
Scenario: Retry limit allows within bounds
Given guardrails with retry limit 3
When I check retries per failure with 2 current retries
Then the retry check should be allowed
Scenario: Retry limit blocks at max
Given guardrails with retry limit 3
When I check retries per failure with 3 current retries
Then the retry check should be denied
Scenario: Retry limit blocks above max
Given guardrails with retry limit 2
When I check retries per failure with 5 current retries
Then the retry check should be denied
Scenario: Unlimited retries always allowed
Given guardrails with no retry limit
When I check retries per failure with 1000 current retries
Then the retry check should be allowed
Scenario: Service retry check records audit trail
Given an autonomy guardrail service with retry-limit guardrails for plan "plan-rl"
When I check retries via service for plan "plan-rl" with 1 retries
Then the audit trail for plan "plan-rl" should have 1 entry
Scenario: Service retry check blocks and records audit trail
Given an autonomy guardrail service with retry-limit guardrails for plan "plan-rl2"
When I check retries via service for plan "plan-rl2" with 5 retries
Then the retry service check should return False
And the audit trail for plan "plan-rl2" should have 1 entry
Scenario: Successive retries stop after reaching max_retries_per_failure
Given a guardrail service with max_retries_per_failure 3 for plan "retry-stop"
When I check retries for plan "retry-stop" incrementing from 0 to 4
Then retry checks 0, 1, 2 should be allowed
And retry checks 3, 4 should be denied
And the audit trail for plan "retry-stop" should have 5 entry
# ---- PlanExecutor guardrail integration ----
Scenario: PlanExecutor enforces step limit during stub execution
Given a plan executor with guardrail service and step limit 2
And a plan in execute phase with 3 decisions
When I run execute on the plan
Then execution should fail with a guardrail step limit error
Scenario: PlanExecutor enforces wall-clock limit during execution
Given a plan executor with guardrail service and expired wall-clock
And a plan in execute phase with 1 decisions
When I run execute on the plan
Then execution should fail with a guardrail wall-clock error
Scenario: PlanExecutor runs without guardrails when service is None
Given a plan executor without guardrail service
And a plan in execute phase with 2 decisions
When I run execute on the plan
Then execution should succeed
Scenario: PlanExecutor marks start_time on first execution
Given a plan executor with guardrail service and no wall-clock limit
And a plan in execute phase with 1 decisions
When I run execute on the plan
Then the guardrails start_time should have been set
# ---- Additional validation edge cases for coverage ----
Scenario: Guardrails reject invalid max_tool_calls_per_invocation
When I try to create actor limits with max_tool_calls_per_invocation 0
Then a guardrails validation error should be raised
And the guardrails error should mention "max_tool_calls_per_invocation"
Scenario: Guardrails reject negative max_retries_per_failure
When I try to create actor limits with max_retries_per_failure -1
Then a guardrails validation error should be raised
And the guardrails error should mention "max_retries_per_failure"
Scenario: Guardrails reject non-positive max_wall_clock_seconds
When I try to create guardrails with max_wall_clock_seconds 0
Then a guardrails validation error should be raised
And the guardrails error should mention "max_wall_clock_seconds"
Scenario: Audit trail evicts denied entry when full
Given an audit trail with max_entries 2
When I add a budget_blocked entry to the audit trail
And I add a step_allowed entry to the audit trail
And I add a step_allowed entry to the audit trail
Then the audit trail should have 2 entries
And the audit trail denied_count should be 0
And the audit trail allowed_count should be 2