55aee7cf22
CI / lint (pull_request) Successful in 18s
CI / quality (pull_request) Successful in 21s
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 14s
CI / security (pull_request) Successful in 49s
CI / typecheck (pull_request) Successful in 56s
CI / integration_tests (pull_request) Successful in 2m35s
CI / unit_tests (pull_request) Successful in 14m30s
CI / docker (pull_request) Successful in 55s
CI / benchmark-regression (pull_request) Successful in 21m11s
CI / coverage (pull_request) Successful in 34m22s
CI / lint (push) Successful in 12s
CI / build (push) Successful in 16s
CI / quality (push) Successful in 17s
CI / security (push) Successful in 29s
CI / typecheck (push) Successful in 1m0s
CI / benchmark-regression (push) Has been skipped
CI / integration_tests (push) Successful in 4m54s
CI / benchmark-publish (push) Successful in 11m48s
CI / unit_tests (push) Successful in 16m30s
CI / docker (push) Successful in 28s
CI / coverage (push) Successful in 25m45s
The step_register_skills_table step called add_skill in a loop but only committed once at the end. Because SkillRepository.create() obtains a new session per call and only flushes (never commits), the intermediate sessions could be garbage-collected before the final commit, rolling back their transactions on the shared SQLite :memory: connection. Moving _commit_pending inside the loop ensures each skill is durably committed before the next session is created. ISSUES CLOSED: #418
343 lines
17 KiB
Gherkin
343 lines
17 KiB
Gherkin
Feature: CorrectionService full coverage
|
||
As a developer maintaining CorrectionService
|
||
I want every line and branch fully tested
|
||
So that correction_service.py achieves 100% coverage
|
||
|
||
Background:
|
||
Given a coverage test correction service
|
||
|
||
# -------------------------------------------------------------------
|
||
# __init__
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Service initializes with empty internal dictionaries
|
||
Then the coverage service corrections dict should be empty
|
||
And the coverage service impacts dict should be empty
|
||
And the coverage service attempts dict should be empty
|
||
And the coverage service results dict should be empty
|
||
|
||
# -------------------------------------------------------------------
|
||
# request_correction – happy paths
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Create a revert correction with defaults
|
||
When I cov-request a correction for plan "P1" targeting "D1" in revert mode
|
||
Then the cov-request should be stored in the service
|
||
And the cov-request plan_id should be "P1"
|
||
And the cov-request target_decision_id should be "D1"
|
||
And the cov-request mode should be "revert"
|
||
And the cov-request status should be "pending"
|
||
And the cov-request dry_run should be false
|
||
And the cov-request guidance should be empty
|
||
|
||
Scenario: Create an append correction with guidance and dry_run
|
||
When I cov-request a correction for plan "P2" targeting "D2" in append mode with guidance "fix things" and dry_run
|
||
Then the cov-request should be stored in the service
|
||
And the cov-request plan_id should be "P2"
|
||
And the cov-request target_decision_id should be "D2"
|
||
And the cov-request mode should be "append"
|
||
And the cov-request dry_run should be true
|
||
And the cov-request guidance should be "fix things"
|
||
|
||
# -------------------------------------------------------------------
|
||
# request_correction – validation errors
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Empty plan_id raises ValidationError
|
||
When I cov-attempt to create a correction with empty plan_id and target "D1"
|
||
Then a cov ValidationError should have been raised
|
||
|
||
Scenario: Whitespace-only plan_id raises ValidationError
|
||
When I cov-attempt to create a correction with plan_id " " and target "D1"
|
||
Then a cov ValidationError should have been raised
|
||
|
||
Scenario: Empty target_decision_id raises ValidationError
|
||
When I cov-attempt to create a correction with plan_id "P1" and empty target
|
||
Then a cov ValidationError should have been raised
|
||
|
||
Scenario: Whitespace-only target_decision_id raises ValidationError
|
||
When I cov-attempt to create a correction with plan_id "P1" and target " "
|
||
Then a cov ValidationError should have been raised
|
||
|
||
# -------------------------------------------------------------------
|
||
# analyze_impact – BFS traversal
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Analyze impact with no decision tree yields single-node result
|
||
Given a cov-stored revert correction for plan "P1" targeting "ROOT"
|
||
When I cov-analyze impact with an empty tree
|
||
Then the cov-impact affected decisions should be "ROOT"
|
||
And the cov-impact risk level should be "low"
|
||
And the cov-impact rollback tier should be "full"
|
||
And the cov-impact estimated cost should be 1.5
|
||
And the cov-impact artifacts to archive should be "ROOT.artifact"
|
||
And the cov-impact affected files should be "ROOT.py"
|
||
|
||
Scenario: Analyze impact with tree having children
|
||
Given a cov-stored revert correction for plan "P1" targeting "A"
|
||
When I cov-analyze impact with adjacency "A->B,C;B->D"
|
||
Then the cov-impact affected decisions should be "A,B,C,D"
|
||
And the cov-impact risk level should be "medium"
|
||
And the cov-impact estimated cost should be 6.0
|
||
And the cov-impact affected decisions count should be 4
|
||
|
||
Scenario: Analyze impact for append mode sets rollback tier to append_only
|
||
Given a cov-stored append correction for plan "P1" targeting "X"
|
||
When I cov-analyze impact with an empty tree
|
||
Then the cov-impact rollback tier should be "append_only"
|
||
|
||
Scenario: Analyze impact for nonexistent correction raises ResourceNotFoundError
|
||
When I cov-attempt to analyze impact for correction id "BOGUS_ID"
|
||
Then a cov ResourceNotFoundError should have been raised
|
||
|
||
Scenario: Analyze impact sets status to analyzing
|
||
Given a cov-stored revert correction for plan "P1" targeting "N1"
|
||
When I cov-analyze impact with an empty tree
|
||
Then the cov-stored correction status should be "analyzing"
|
||
|
||
# -------------------------------------------------------------------
|
||
# generate_dry_run_report
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Dry-run report for low-risk revert with single decision
|
||
Given a cov-stored revert correction for plan "P1" targeting "SOLO"
|
||
When I cov-generate dry-run report with an empty tree
|
||
Then the cov dry-run mode should be "revert"
|
||
And the cov dry-run warnings should be empty
|
||
And the cov dry-run decisions to invalidate should be "SOLO"
|
||
And the cov dry-run estimated recompute time should be 2.0
|
||
|
||
Scenario: Dry-run report for medium-risk revert with multiple decisions
|
||
Given a cov-stored revert correction for plan "P1" targeting "R"
|
||
When I cov-generate dry-run report with adjacency "R->C1,C2,C3,C4"
|
||
Then the cov dry-run warnings should contain "Medium risk"
|
||
And the cov dry-run warnings should contain "Revert will invalidate 5 decisions"
|
||
And the cov dry-run decisions to invalidate count should be 5
|
||
And the cov dry-run estimated recompute time should be 10.0
|
||
|
||
Scenario: Dry-run report for high-risk revert
|
||
Given a cov-stored revert correction for plan "P1" targeting "H"
|
||
When I cov-generate dry-run report with a chain of 12 nodes rooted at "H"
|
||
Then the cov dry-run warnings should contain "High risk"
|
||
And the cov dry-run warnings should contain "Revert will invalidate 12 decisions"
|
||
And the cov dry-run decisions to invalidate count should be 12
|
||
|
||
Scenario: Dry-run report for append mode has empty decisions_to_invalidate
|
||
Given a cov-stored append correction for plan "P1" targeting "APP"
|
||
When I cov-generate dry-run report with an empty tree
|
||
Then the cov dry-run mode should be "append"
|
||
And the cov dry-run decisions to invalidate should be empty list
|
||
And the cov dry-run warnings should be empty
|
||
|
||
Scenario: Dry-run report for nonexistent correction raises error
|
||
When I cov-attempt to generate dry-run report for correction id "NO_SUCH"
|
||
Then a cov ResourceNotFoundError should have been raised
|
||
|
||
# -------------------------------------------------------------------
|
||
# execute_revert
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Execute revert on a pending correction succeeds
|
||
Given a cov-stored revert correction for plan "P1" targeting "T1"
|
||
When I cov-execute revert with adjacency "T1->T2"
|
||
Then the cov revert result status should be "applied"
|
||
And the cov revert result reverted decisions should include "T1"
|
||
And the cov revert result reverted decisions should include "T2"
|
||
And the cov revert result archived artifacts should include "T1.artifact"
|
||
And the cov revert result archived artifacts should include "T2.artifact"
|
||
And the cov-stored correction status should be "applied"
|
||
And the cov attempts for the stored correction should have 1 entry
|
||
And the cov first attempt should be successful
|
||
And the cov first attempt completed_at should be set
|
||
|
||
Scenario: Execute revert with empty tree marks only the target
|
||
Given a cov-stored revert correction for plan "P1" targeting "ONLY"
|
||
When I cov-execute revert with empty tree
|
||
Then the cov revert result status should be "applied"
|
||
And the cov revert result reverted decisions should include "ONLY"
|
||
|
||
Scenario: Execute revert on already-applied correction raises ValidationError
|
||
Given a cov-stored revert correction for plan "P1" targeting "R1"
|
||
And the cov-stored correction has been executed via revert with empty tree
|
||
When I cov-attempt to execute revert on the stored correction
|
||
Then a cov ValidationError should have been raised
|
||
|
||
# -------------------------------------------------------------------
|
||
# execute_append
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Execute append on a pending correction succeeds
|
||
Given a cov-stored append correction for plan "P1" targeting "A1"
|
||
When I cov-execute append for the stored correction
|
||
Then the cov append result status should be "applied"
|
||
And the cov append result spawned_child_plan_id should not be none
|
||
And the cov append result new_decisions should not be empty
|
||
And the cov-stored correction status should be "applied"
|
||
And the cov attempts for the stored correction should have 1 entry
|
||
And the cov first attempt should be successful
|
||
And the cov first attempt details should contain spawned_child_plan_id
|
||
|
||
Scenario: Execute append on already-applied correction raises ValidationError
|
||
Given a cov-stored append correction for plan "P1" targeting "A2"
|
||
And the cov-stored correction has been executed via append
|
||
When I cov-attempt to execute append on the stored correction
|
||
Then a cov ValidationError should have been raised
|
||
|
||
# -------------------------------------------------------------------
|
||
# execute_correction (dispatch)
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Dispatch routes revert mode to execute_revert
|
||
Given a cov-stored revert correction for plan "P1" targeting "DR"
|
||
When I cov-dispatch execute correction with adjacency "DR->DR2"
|
||
Then the cov dispatch result status should be "applied"
|
||
And the cov dispatch result reverted decisions should include "DR"
|
||
And the cov dispatch result reverted decisions should include "DR2"
|
||
|
||
Scenario: Dispatch routes append mode to execute_append
|
||
Given a cov-stored append correction for plan "P1" targeting "DA"
|
||
When I cov-dispatch execute correction with no tree
|
||
Then the cov dispatch result status should be "applied"
|
||
And the cov dispatch result spawned_child_plan_id should not be none
|
||
|
||
# -------------------------------------------------------------------
|
||
# get_correction
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Get correction by id returns correct request
|
||
Given a cov-stored revert correction for plan "PG" targeting "DG"
|
||
When I cov-get the stored correction by id
|
||
Then the cov-retrieved correction plan_id should be "PG"
|
||
And the cov-retrieved correction target_decision_id should be "DG"
|
||
|
||
Scenario: Get correction for nonexistent id raises ResourceNotFoundError
|
||
When I cov-attempt to get correction with id "MISSING"
|
||
Then a cov ResourceNotFoundError should have been raised
|
||
|
||
# -------------------------------------------------------------------
|
||
# list_corrections
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: List all corrections without filter
|
||
Given a cov-stored revert correction for plan "PA" targeting "DA"
|
||
And a cov-stored revert correction for plan "PB" targeting "DB"
|
||
When I cov-list all corrections without filter
|
||
Then the cov corrections list should have at least 2 items
|
||
|
||
Scenario: List corrections filtered by plan_id
|
||
Given a cov-stored revert correction for plan "PX" targeting "DX"
|
||
Given a cov-stored append correction for plan "PY" targeting "DY"
|
||
When I cov-list corrections for plan "PX"
|
||
Then the cov corrections list should have 1 item
|
||
|
||
Scenario: List corrections filtered by plan_id with no matches
|
||
When I cov-list corrections for plan "NONEXISTENT_PLAN"
|
||
Then the cov corrections list should have 0 items
|
||
|
||
# -------------------------------------------------------------------
|
||
# list_attempts
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: List attempts before any execution returns empty
|
||
Given a cov-stored revert correction for plan "P1" targeting "D1"
|
||
When I cov-list attempts for the stored correction
|
||
Then the cov attempts list should have 0 items
|
||
|
||
Scenario: List attempts after execution returns the attempt
|
||
Given a cov-stored revert correction for plan "P1" targeting "D1"
|
||
And the cov-stored correction has been executed via revert with empty tree
|
||
When I cov-list attempts for the stored correction
|
||
Then the cov attempts list should have 1 item
|
||
|
||
Scenario: List attempts for nonexistent correction raises error
|
||
When I cov-attempt to list attempts for correction id "NOPE"
|
||
Then a cov ResourceNotFoundError should have been raised
|
||
|
||
# -------------------------------------------------------------------
|
||
# cancel_correction
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Cancel a pending correction succeeds
|
||
Given a cov-stored revert correction for plan "P1" targeting "D1"
|
||
When I cov-cancel the stored correction
|
||
Then the cov-stored correction status should be "cancelled"
|
||
|
||
Scenario: Cancel an analyzing correction succeeds
|
||
Given a cov-stored revert correction for plan "P1" targeting "D1"
|
||
And the cov-stored correction has been analyzed with empty tree
|
||
When I cov-cancel the stored correction
|
||
Then the cov-stored correction status should be "cancelled"
|
||
|
||
Scenario: Cancel an already-applied correction raises ValidationError
|
||
Given a cov-stored revert correction for plan "P1" targeting "D1"
|
||
And the cov-stored correction has been executed via revert with empty tree
|
||
When I cov-attempt to cancel the stored correction
|
||
Then a cov ValidationError should have been raised
|
||
|
||
Scenario: Cancel an already-cancelled correction raises ValidationError
|
||
Given a cov-stored revert correction for plan "P1" targeting "D1"
|
||
When I cov-cancel the stored correction
|
||
And I cov-attempt to cancel the stored correction
|
||
Then a cov ValidationError should have been raised
|
||
|
||
# -------------------------------------------------------------------
|
||
# _classify_risk (static)
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario Outline: Risk classification boundary values
|
||
Then cov classifying risk for <count> affected returns "<expected>"
|
||
|
||
Examples:
|
||
| count | expected |
|
||
| 0 | low |
|
||
| 1 | low |
|
||
| 3 | low |
|
||
| 4 | medium |
|
||
| 10 | medium |
|
||
| 11 | high |
|
||
| 50 | high |
|
||
|
||
# -------------------------------------------------------------------
|
||
# _compute_affected_subtree (static)
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Compute affected subtree with empty tree returns only root
|
||
When I cov-compute subtree for "ROOT" with empty tree
|
||
Then the cov subtree should be "ROOT"
|
||
|
||
Scenario: Compute affected subtree with linear chain
|
||
When I cov-compute subtree for "A" with adjacency "A->B;B->C;C->D"
|
||
Then the cov subtree should be "A,B,C,D"
|
||
And the cov subtree count should be 4
|
||
|
||
Scenario: Compute affected subtree with branching tree
|
||
When I cov-compute subtree for "R" with adjacency "R->L,M;L->LL,LR"
|
||
Then the cov subtree should be "R,L,M,LL,LR"
|
||
|
||
Scenario: Compute affected subtree starting at leaf node
|
||
When I cov-compute subtree for "LEAF" with adjacency "ROOT->LEAF"
|
||
Then the cov subtree should be "LEAF"
|
||
And the cov subtree count should be 1
|
||
|
||
# -------------------------------------------------------------------
|
||
# _assert_executable internal helper (via execute_revert / execute_append)
|
||
# -------------------------------------------------------------------
|
||
|
||
Scenario: Execute revert on FAILED correction raises ValidationError
|
||
Given a cov-stored revert correction for plan "P1" targeting "F1"
|
||
And the cov-stored correction status is forced to "failed"
|
||
When I cov-attempt to execute revert on the stored correction
|
||
Then a cov ValidationError should have been raised
|
||
|
||
Scenario: Execute append on EXECUTING correction raises ValidationError
|
||
Given a cov-stored append correction for plan "P1" targeting "E1"
|
||
And the cov-stored correction status is forced to "executing"
|
||
When I cov-attempt to execute append on the stored correction
|
||
Then a cov ValidationError should have been raised
|
||
|
||
Scenario: Execute append on CANCELLED correction raises ValidationError
|
||
Given a cov-stored append correction for plan "P1" targeting "C1"
|
||
And the cov-stored correction status is forced to "cancelled"
|
||
When I cov-attempt to execute append on the stored correction
|
||
Then a cov ValidationError should have been raised
|