3cf3f1f69e
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 15s
CI / lint (pull_request) Successful in 3m40s
CI / quality (pull_request) Successful in 4m13s
CI / security (pull_request) Successful in 4m16s
CI / typecheck (pull_request) Successful in 4m16s
CI / integration_tests (pull_request) Successful in 9m11s
CI / unit_tests (pull_request) Successful in 9m23s
CI / docker (pull_request) Successful in 1m18s
CI / coverage (pull_request) Successful in 11m48s
CI / status-check (pull_request) Successful in 7s
CI / e2e_tests (pull_request) Successful in 8m24s
CI / lint (push) Successful in 3m18s
CI / build (push) Failing after 13s
CI / typecheck (push) Successful in 3m54s
CI / benchmark-regression (push) Has been skipped
CI / quality (push) Successful in 4m15s
CI / security (push) Successful in 4m39s
CI / integration_tests (push) Successful in 7m21s
CI / unit_tests (push) Successful in 7m44s
CI / docker (push) Successful in 1m9s
CI / e2e_tests (push) Successful in 11m9s
CI / coverage (push) Successful in 13m41s
CI / status-check (push) Successful in 2s
CI / benchmark-regression (pull_request) Successful in 48m49s
CI / benchmark-publish (push) Successful in 26m25s
Implemented FixThenRevalidateOrchestrator with full diagnosis → self-fix → re-validation → retry limit → strategy revision → user escalation → terminal failure flow. Added retry counting per validation per plan, configurable retry limit (default 3), auto_strategy_revision flag support, and validation_fix_history recording in plan execution metadata. Review fixes applied (round 1): - Added try/except around fix_callback and revalidate_callback (spec: validation errors treated as required failure regardless of mode) - Wired optional EventBus for VALIDATION_FIX_ATTEMPTED/SUCCEEDED/EXHAUSTED events - Fixed total_attempts derivation from fix_history length instead of cumulative retry counts - Updated module docstring to reflect implemented vs caller-responsible steps - Added exhausted-retry logging on re-invocation - Replaced bare assert in Robot helper with explicit _check() function - Added 10 new Behave scenarios covering exception paths, multi-failure, reset, field validation, boundary values, event_bus property, and exhausted re-invocation Review fixes applied (round 2 — PR #711): - B1+B7: Fixed TOCTOU race in _fix_single_validation; atomic claim-per-iteration under RLock; eliminated defaultdict auto-vivification with .get() reads - B2: Added validation_name mismatch check on revalidate_callback return - B3: Added fix_description truncation to 2000 chars before FixAttemptRecord - T1: Switched threading.Lock to threading.RLock for defensive reentrancy - A1: Added model_validator preventing escalated+terminal_failure both True - R1: Added max_length=255 to FixAttemptRecord.validation_name - S7: Fixed misleading docstring about automation_profile integration - D4: Fixed timestamp field description to specify UTC - D1: Renamed misleading benchmark time_fix_after_two_retries - Added 5 new Behave scenarios for truncation, model constraints, name mismatch ISSUES CLOSED: #583
349 lines
21 KiB
Gherkin
349 lines
21 KiB
Gherkin
Feature: Fix-then-Revalidate coverage boost
|
|
As a developer
|
|
I want to cover edge cases and validation paths in FixThenRevalidateOrchestrator
|
|
So that code coverage meets the 97% threshold
|
|
|
|
# Covers: __init__ validation
|
|
Scenario: Orchestrator rejects None validation_pipeline
|
|
When the fix-revalidate orchestrator is created with None pipeline
|
|
Then a fix-revalidate validation error should be raised with "validation_pipeline must not be None"
|
|
|
|
# Covers: __init__ validation
|
|
Scenario: Orchestrator rejects non-integer max_retries
|
|
When the fix-revalidate orchestrator is created with non-integer max_retries
|
|
Then a fix-revalidate validation error should be raised with "max_retries must be an integer"
|
|
|
|
# Covers: __init__ validation
|
|
Scenario: Orchestrator rejects max_retries below minimum
|
|
When the fix-revalidate orchestrator is created with max_retries -1
|
|
Then a fix-revalidate validation error should be raised with "max_retries must be between"
|
|
|
|
# Covers: __init__ validation
|
|
Scenario: Orchestrator rejects max_retries above maximum
|
|
When the fix-revalidate orchestrator is created with max_retries 101
|
|
Then a fix-revalidate validation error should be raised with "max_retries must be between"
|
|
|
|
# Covers: max_retries property
|
|
Scenario: Orchestrator exposes max_retries property
|
|
Given a fix-revalidate coverage orchestrator with max_retries 5
|
|
Then the fix-revalidate max_retries property should return 5
|
|
|
|
# Covers: auto_strategy_revision property
|
|
Scenario: Orchestrator exposes auto_strategy_revision property
|
|
Given a fix-revalidate coverage orchestrator with auto_strategy_revision enabled
|
|
Then the fix-revalidate auto_strategy_revision property should be 0.0
|
|
|
|
# Covers: get_retry_count empty plan_id
|
|
Scenario: get_retry_count rejects empty plan_id
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
When the fix-revalidate get_retry_count is called with empty plan_id
|
|
Then a fix-revalidate validation error should be raised with "plan_id must not be empty"
|
|
|
|
# Covers: get_retry_count empty validation_name
|
|
Scenario: get_retry_count rejects empty validation_name
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
When the fix-revalidate get_retry_count is called with empty validation_name
|
|
Then a fix-revalidate validation error should be raised with "validation_name must not be empty"
|
|
|
|
# Covers: get_retry_count returns count
|
|
Scenario: get_retry_count returns zero for unseen validation
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
Then the fix-revalidate get_retry_count for plan "P1" validation "check-a" should be 0
|
|
|
|
# Covers: reset_retry_counts empty plan_id
|
|
Scenario: reset_retry_counts rejects empty plan_id
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
When the fix-revalidate reset_retry_counts is called with empty plan_id
|
|
Then a fix-revalidate validation error should be raised with "plan_id must not be empty"
|
|
|
|
# Covers: run_fix_loop empty plan_id
|
|
Scenario: run_fix_loop rejects empty plan_id
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
When the fix-revalidate run_fix_loop is called with empty plan_id
|
|
Then a fix-revalidate validation error should be raised with "plan_id must not be empty"
|
|
|
|
# Covers: run_fix_loop None failed_results
|
|
Scenario: run_fix_loop rejects None failed_results
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
When the fix-revalidate run_fix_loop is called with None failed_results
|
|
Then a fix-revalidate validation error should be raised with "failed_results must not be None"
|
|
|
|
# Covers: run_fix_loop None fix_callback
|
|
Scenario: run_fix_loop rejects None fix_callback
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
When the fix-revalidate run_fix_loop is called with None fix_callback
|
|
Then a fix-revalidate validation error should be raised with "fix_callback must not be None"
|
|
|
|
# Covers: run_fix_loop None revalidate_callback
|
|
Scenario: run_fix_loop rejects None revalidate_callback
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
When the fix-revalidate run_fix_loop is called with None revalidate_callback
|
|
Then a fix-revalidate validation error should be raised with "revalidate_callback must not be None"
|
|
|
|
# Covers: fix_callback exception handling
|
|
Scenario: fix_callback exception is treated as failed attempt
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
And a required coverage validation "check-syntax" that fails
|
|
And a fix-revalidate coverage fix callback that raises an exception
|
|
And a fix-revalidate coverage revalidate callback that never passes
|
|
When the fix-revalidate coverage loop runs for plan "P-EXC1"
|
|
Then the fix-revalidate coverage result should have final_passed False
|
|
And the fix-revalidate coverage result should need user escalation
|
|
And the fix-revalidate coverage validation fix history should have 3 records
|
|
And each fix-revalidate coverage validation fix history record should have success False
|
|
|
|
# Covers: revalidate_callback exception handling
|
|
Scenario: revalidate_callback exception is treated as failed validation
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
And a required coverage validation "check-lint" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that raises an exception
|
|
When the fix-revalidate coverage loop runs for plan "P-EXC2"
|
|
Then the fix-revalidate coverage result should have final_passed False
|
|
And the fix-revalidate coverage result should need user escalation
|
|
And the fix-revalidate coverage validation fix history should have 3 records
|
|
|
|
# Covers: multiple simultaneous validation failures
|
|
Scenario: Multiple validations fail simultaneously with mixed outcomes
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
And a required coverage validation "check-a" that fails
|
|
And a required coverage validation "check-b" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback where check-a passes after 1 and check-b never passes
|
|
When the fix-revalidate coverage loop runs for plan "P-MULTI"
|
|
Then the fix-revalidate coverage result should have final_passed False
|
|
And the fix-revalidate coverage result should need user escalation
|
|
And the fix-revalidate coverage validation fix history should have 4 records
|
|
|
|
# Covers: reset_retry_counts then re-run
|
|
Scenario: Reset retry counts allows fresh retry budget
|
|
Given a fix-revalidate coverage orchestrator with max_retries 2
|
|
And a required coverage validation "check-retry" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that never passes
|
|
When the fix-revalidate coverage loop runs for plan "P-RESET"
|
|
And the fix-revalidate coverage retry counts are reset for plan "P-RESET"
|
|
And a fix-revalidate coverage revalidate callback that passes after 1
|
|
And the fix-revalidate coverage loop runs again for plan "P-RESET" with validation "check-retry"
|
|
Then the fix-revalidate coverage result should have final_passed True
|
|
And the fix-revalidate coverage result should have validation_attempts 1
|
|
|
|
# Covers: validation fix history record field validation
|
|
Scenario: Fix history records contain correct field values
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
And a required coverage validation "check-fields" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that passes after 2
|
|
When the fix-revalidate coverage loop runs for plan "P-FIELDS"
|
|
Then the fix-revalidate coverage validation fix history should have 2 records
|
|
And fix-revalidate coverage validation fix history record 1 should have validation_name "check-fields"
|
|
And fix-revalidate coverage validation fix history record 1 should have attempt_number 1
|
|
And fix-revalidate coverage validation fix history record 1 should have success False
|
|
And fix-revalidate coverage validation fix history record 2 should have success True
|
|
|
|
# Covers: max_retries=1 boundary
|
|
Scenario: Fix loop works with max_retries 1
|
|
Given a fix-revalidate coverage orchestrator with max_retries 1
|
|
And a required coverage validation "check-bound1" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that passes after 1
|
|
When the fix-revalidate coverage loop runs for plan "P-BOUND1"
|
|
Then the fix-revalidate coverage result should have final_passed True
|
|
And the fix-revalidate coverage result should have validation_attempts 1
|
|
|
|
# Covers: max_retries=10 boundary
|
|
Scenario: Fix loop works with max_retries 10
|
|
Given a fix-revalidate coverage orchestrator with max_retries 10
|
|
And a required coverage validation "check-bound10" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that passes after 9
|
|
When the fix-revalidate coverage loop runs for plan "P-BOUND10"
|
|
Then the fix-revalidate coverage result should have final_passed True
|
|
And the fix-revalidate coverage result should have validation_attempts 9
|
|
|
|
# Covers: event_bus property
|
|
Scenario: Orchestrator exposes event_bus property
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
Then the fix-revalidate event_bus property should be None
|
|
|
|
# Covers: exhausted re-invocation with auto-reset
|
|
Scenario: Second invocation for exhausted validation logs warning
|
|
Given a fix-revalidate coverage orchestrator with max_retries 1
|
|
And a required coverage validation "check-exhausted" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that never passes
|
|
When the fix-revalidate coverage loop runs for plan "P-EXHAUST"
|
|
And the fix-revalidate coverage loop runs again for plan "P-EXHAUST" with validation "check-exhausted"
|
|
Then the fix-revalidate coverage result should have final_passed False
|
|
And the fix-revalidate coverage result should have validation_attempts 1
|
|
And the fix-revalidate coverage result should need user escalation
|
|
|
|
# Covers: bool type rejected for max_retries
|
|
Scenario: Orchestrator rejects boolean max_retries True
|
|
When the fix-revalidate orchestrator is created with boolean max_retries True
|
|
Then a fix-revalidate validation error should be raised with "max_retries must be an integer"
|
|
|
|
Scenario: Orchestrator rejects boolean max_retries False
|
|
When the fix-revalidate orchestrator is created with boolean max_retries False
|
|
Then a fix-revalidate validation error should be raised with "max_retries must be an integer"
|
|
|
|
# Covers: EventBus domain event emission
|
|
Scenario: EventBus receives VALIDATION_FIX_ATTEMPTED and SUCCEEDED events on fix success
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3 and a mock event bus
|
|
And a required coverage validation "check-events" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that passes after 1
|
|
When the fix-revalidate coverage loop runs for plan "P-EVENTS"
|
|
Then the mock event bus should have received 2 events
|
|
And mock event bus event 1 should have event_type "validation.fix_attempted"
|
|
And mock event bus event 2 should have event_type "validation.fix_succeeded"
|
|
|
|
Scenario: EventBus receives VALIDATION_FIX_EXHAUSTED event on exhaustion
|
|
Given a fix-revalidate coverage orchestrator with max_retries 1 and a mock event bus
|
|
And a required coverage validation "check-exhaust-evt" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that never passes
|
|
When the fix-revalidate coverage loop runs for plan "P-EXHEVT"
|
|
Then the fix-revalidate coverage result should need user escalation
|
|
And the mock event bus should have received 2 events
|
|
And mock event bus event 1 should have event_type "validation.fix_attempted"
|
|
And mock event bus event 2 should have event_type "validation.fix_exhausted"
|
|
|
|
Scenario: EventBus emit exception does not crash the fix loop
|
|
Given a fix-revalidate coverage orchestrator with max_retries 1 and a failing event bus
|
|
And a required coverage validation "check-bus-err" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that passes after 1
|
|
When the fix-revalidate coverage loop runs for plan "P-BUSERR"
|
|
Then the fix-revalidate coverage result should have final_passed True
|
|
|
|
# Covers: FixAttemptRecord Pydantic field constraints
|
|
Scenario: FixAttemptRecord rejects attempt_number below 1
|
|
When a fix-revalidate FixAttemptRecord is created with attempt_number 0
|
|
Then a fix-revalidate pydantic validation error should be raised
|
|
|
|
Scenario: FixAttemptRecord rejects whitespace-only validation_name
|
|
When a fix-revalidate FixAttemptRecord is created with whitespace validation_name
|
|
Then a fix-revalidate pydantic validation error should be raised
|
|
|
|
# Covers: fix_description truncation to 2000 chars
|
|
Scenario: Fix callback returning over-length description is truncated
|
|
Given a fix-revalidate coverage orchestrator with max_retries 1
|
|
And a required coverage validation "check-trunc" that fails
|
|
And a fix-revalidate coverage fix callback that returns a 3000 char description
|
|
And a fix-revalidate coverage revalidate callback that passes after 1
|
|
When the fix-revalidate coverage loop runs for plan "P-TRUNC"
|
|
Then the fix-revalidate coverage result should have final_passed True
|
|
And the fix-revalidate coverage validation fix history should have 1 records
|
|
And fix-revalidate coverage validation fix history record 1 fix_description should be at most 2000 chars
|
|
|
|
# Covers: FixThenRevalidateResult model_validator
|
|
Scenario: FixThenRevalidateResult rejects escalated and terminal_failure both True
|
|
When a fix-revalidate FixThenRevalidateResult is created with escalated True and terminal_failure True
|
|
Then a fix-revalidate pydantic validation error should be raised
|
|
|
|
# Covers: validation_name max_length on FixAttemptRecord
|
|
Scenario: FixAttemptRecord rejects validation_name exceeding 255 chars
|
|
When a fix-revalidate FixAttemptRecord is created with validation_name exceeding 255 chars
|
|
Then a fix-revalidate pydantic validation error should be raised
|
|
|
|
# Covers: revalidate callback returning mismatched validation_name
|
|
Scenario: Revalidate callback returning wrong validation_name is treated as failure
|
|
Given a fix-revalidate coverage orchestrator with max_retries 2
|
|
And a required coverage validation "check-mismatch" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that returns a different validation_name
|
|
When the fix-revalidate coverage loop runs for plan "P-MISMATCH"
|
|
Then the fix-revalidate coverage result should have final_passed False
|
|
And the fix-revalidate coverage result should need user escalation
|
|
|
|
# Covers: auto_strategy_revision type validation
|
|
Scenario: Orchestrator rejects boolean auto_strategy_revision
|
|
When the fix-revalidate orchestrator is created with boolean auto_strategy_revision
|
|
Then a fix-revalidate validation error should be raised with "auto_strategy_revision must be a float"
|
|
|
|
# Covers: auto_strategy_revision range validation
|
|
Scenario: Orchestrator rejects auto_strategy_revision out of range
|
|
When the fix-revalidate orchestrator is created with auto_strategy_revision 1.5
|
|
Then a fix-revalidate validation error should be raised with "auto_strategy_revision must be between"
|
|
|
|
# Covers: auto_validation_fix type validation
|
|
Scenario: Orchestrator rejects boolean auto_validation_fix
|
|
When the fix-revalidate orchestrator is created with boolean auto_validation_fix
|
|
Then a fix-revalidate validation error should be raised with "auto_validation_fix must be a float"
|
|
|
|
# Covers: auto_validation_fix range validation
|
|
Scenario: Orchestrator rejects auto_validation_fix out of range
|
|
When the fix-revalidate orchestrator is created with auto_validation_fix -0.1
|
|
Then a fix-revalidate validation error should be raised with "auto_validation_fix must be between"
|
|
|
|
# Covers: event_bus type validation
|
|
Scenario: Orchestrator rejects non-EventBus event_bus
|
|
When the fix-revalidate orchestrator is created with invalid event_bus type
|
|
Then a fix-revalidate validation error should be raised with "event_bus must be an EventBus"
|
|
|
|
# Covers: callable() validation on fix_callback
|
|
Scenario: run_fix_loop rejects non-callable fix_callback
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
When the fix-revalidate run_fix_loop is called with non-callable fix_callback
|
|
Then a fix-revalidate validation error should be raised with "fix_callback must be callable"
|
|
|
|
# Covers: callable() validation on revalidate_callback
|
|
Scenario: run_fix_loop rejects non-callable revalidate_callback
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
When the fix-revalidate run_fix_loop is called with non-callable revalidate_callback
|
|
Then a fix-revalidate validation error should be raised with "revalidate_callback must be callable"
|
|
|
|
# Covers: fix_callback returning None signals unfixable
|
|
Scenario: Fix callback returning None escalates immediately
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
And a required coverage validation "check-unfixable" that fails
|
|
And a fix-revalidate coverage fix callback that returns None
|
|
And a fix-revalidate coverage revalidate callback that never passes
|
|
When the fix-revalidate coverage loop runs for plan "P-UNFIXABLE"
|
|
Then the fix-revalidate coverage result should have final_passed False
|
|
And the fix-revalidate coverage result should need user escalation
|
|
And the fix-revalidate coverage validation fix history should have 1 records
|
|
|
|
# Covers: passed=True with error treated as failure
|
|
Scenario: Revalidate returning passed True with error is treated as failure
|
|
Given a fix-revalidate coverage orchestrator with max_retries 1
|
|
And a required coverage validation "check-contradictory" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that returns passed with error
|
|
When the fix-revalidate coverage loop runs for plan "P-CONTRADICT"
|
|
Then the fix-revalidate coverage result should have final_passed False
|
|
And the fix-revalidate coverage result should need user escalation
|
|
|
|
# Covers: final_passed=True with escalated=True rejected
|
|
Scenario: FixThenRevalidateResult rejects final_passed True with escalated True
|
|
When a fix-revalidate FixThenRevalidateResult is created with final_passed True and escalated True
|
|
Then a fix-revalidate pydantic validation error should be raised
|
|
|
|
# Covers: auto_validation_fix property accessor
|
|
Scenario: Orchestrator exposes auto_validation_fix property
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
Then the fix-revalidate auto_validation_fix property should be 0.0
|
|
|
|
# Covers: EventBus receives VALIDATION_FIX_EXHAUSTED on escalation path
|
|
Scenario: EventBus receives VALIDATION_FIX_EXHAUSTED event on escalation
|
|
Given a fix-revalidate coverage orchestrator with max_retries 1 and mock event bus and escalation
|
|
And a required coverage validation "check-esc-evt" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that never passes
|
|
When the fix-revalidate coverage loop runs for plan "P-ESCEVT"
|
|
Then the mock event bus should have received 2 events
|
|
And mock event bus event 1 should have event_type "validation.fix_attempted"
|
|
And mock event bus event 2 should have event_type "validation.fix_exhausted"
|
|
|
|
# Covers: mixed required and informational failures
|
|
Scenario: Mixed required and informational failures only fix required
|
|
Given a fix-revalidate coverage orchestrator with max_retries 3
|
|
And a required coverage validation "check-req" that fails
|
|
And an informational coverage validation "check-info" that fails
|
|
And a fix-revalidate coverage fix callback that always succeeds
|
|
And a fix-revalidate coverage revalidate callback that passes after 1
|
|
When the fix-revalidate coverage loop runs for plan "P-MIXED"
|
|
Then the fix-revalidate coverage result should have final_passed True
|
|
And the fix-revalidate coverage result should have validation_attempts 1
|