8e6642e8c9
CI / lint (pull_request) Successful in 13s
CI / typecheck (pull_request) Successful in 31s
CI / security (pull_request) Successful in 32s
CI / quality (pull_request) Successful in 15s
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 1m17s
CI / integration_tests (pull_request) Successful in 2m50s
CI / coverage (pull_request) Successful in 4m16s
CI / unit_tests (pull_request) Successful in 6m28s
CI / docker (pull_request) Successful in 39s
CI / lint (push) Successful in 12s
CI / typecheck (push) Successful in 31s
CI / security (push) Successful in 29s
CI / quality (push) Successful in 15s
CI / build (push) Successful in 21s
CI / unit_tests (push) Successful in 2m11s
CI / benchmark-regression (push) Has been skipped
CI / docker (push) Successful in 40s
CI / integration_tests (push) Successful in 2m58s
CI / coverage (push) Successful in 6m20s
CI / benchmark-publish (push) Successful in 14m5s
CI / benchmark-regression (pull_request) Successful in 33m18s
Extended _compute_affected_subtree() to BFS over both the structural tree (parent-child plan relationships) and decision_dependencies edges (influence DAG). The algorithm performs a single O(V+E) BFS pass that unions neighbors from both edge sources, using a visited set for cycle detection to guard against data corruption. Decision creation now supports dependency_decision_ids parameter in record_decision() which populates the in-memory influence DAG store. get_influence_edges() returns the adjacency list format consumed by CorrectionService. All public CorrectionService methods (analyze_impact, execute_revert, execute_correction, generate_dry_run_report) accept an optional influence_edges parameter while remaining backward-compatible (defaults to None, preserving structural-only traversal when not provided). Key design decisions: - Single BFS pass over union of structural + influence edges rather than separate traversals, ensuring O(V+E) complexity and consistent visit order - Cycle detection via visited set with warning log (not an error) since cycles indicate data corruption, not a programming error - Influence edge logging: traversal emits count of influence edges processed for observability - Backward-compatible API: existing callers that only pass decision_tree continue to work identically ISSUES CLOSED: #542
125 lines
5.6 KiB
Gherkin
125 lines
5.6 KiB
Gherkin
Feature: Influence DAG traversal in correction affected subtree
|
|
The affected subtree computation must traverse BOTH the structural
|
|
tree (parent-child) AND the influence DAG (decision_dependencies)
|
|
edges so that corrections cascade through influence relationships.
|
|
|
|
# ================================================================
|
|
# Structural-only (existing behaviour preserved)
|
|
# ================================================================
|
|
|
|
Scenario: Structural-only subtree with no influence edges
|
|
Given an influence-aware correction service
|
|
And a correction request targeting decision "D1" in plan "P1" for revert
|
|
And a structural tree where "D1" has children "D2,D3" and "D2" has children "D4"
|
|
And no influence edges
|
|
When I analyze the impact with influence support
|
|
Then the affected decision set should be "D1,D2,D3,D4"
|
|
|
|
|
|
Scenario: Structural-only single node
|
|
Given an influence-aware correction service
|
|
And a correction request targeting decision "D1" in plan "P1" for revert
|
|
And a structural tree with no children for "D1"
|
|
And no influence edges
|
|
When I analyze the impact with influence support
|
|
Then the affected decision set should be "D1"
|
|
|
|
|
|
# ================================================================
|
|
# Influence-only (new behaviour)
|
|
# ================================================================
|
|
|
|
Scenario: Influence-only affected subtree finds linked decisions
|
|
Given an influence-aware correction service
|
|
And a correction request targeting decision "D1" in plan "P1" for revert
|
|
And a structural tree with no children for "D1"
|
|
And influence edges where "D1" influences "D5,D6" and "D5" influences "D7"
|
|
When I analyze the impact with influence support
|
|
Then the affected decision set should be "D1,D5,D6,D7"
|
|
|
|
|
|
Scenario: Influence-only with no structural children
|
|
Given an influence-aware correction service
|
|
And a correction request targeting decision "DX" in plan "P1" for revert
|
|
And a structural tree with no children for "DX"
|
|
And influence edges where "DX" influences "DY"
|
|
When I analyze the impact with influence support
|
|
Then the affected decision set should be "DX,DY"
|
|
|
|
|
|
# ================================================================
|
|
# Combined structural + influence (union)
|
|
# ================================================================
|
|
|
|
Scenario: Combined structural and influence subtree is the union
|
|
Given an influence-aware correction service
|
|
And a correction request targeting decision "D1" in plan "P1" for revert
|
|
And a structural tree where "D1" has children "D2,D3"
|
|
And influence edges where "D1" influences "D4" and "D3" influences "D5"
|
|
When I analyze the impact with influence support
|
|
Then the affected decision set should be "D1,D2,D3,D4,D5"
|
|
|
|
|
|
Scenario: Overlapping structural and influence edges deduplicate
|
|
Given an influence-aware correction service
|
|
And a correction request targeting decision "D1" in plan "P1" for revert
|
|
And a structural tree where "D1" has children "D2"
|
|
And influence edges where "D1" influences "D2"
|
|
When I analyze the impact with influence support
|
|
Then the affected decision set should be "D1,D2"
|
|
|
|
|
|
# ================================================================
|
|
# Cycle detection (corrupt data)
|
|
# ================================================================
|
|
|
|
Scenario: Cycle in influence DAG is handled gracefully
|
|
Given an influence-aware correction service
|
|
And a correction request targeting decision "D1" in plan "P1" for revert
|
|
And a structural tree with no children for "D1"
|
|
And influence edges with a cycle "D1" to "D2" to "D3" back to "D1"
|
|
When I analyze the impact with influence support
|
|
Then the affected decision set should be "D1,D2,D3"
|
|
And no infinite loop occurred
|
|
|
|
|
|
Scenario: Self-loop in influence DAG is handled gracefully
|
|
Given an influence-aware correction service
|
|
And a correction request targeting decision "D1" in plan "P1" for revert
|
|
And a structural tree with no children for "D1"
|
|
And influence edges where "D1" influences "D1"
|
|
When I analyze the impact with influence support
|
|
Then the affected decision set should be "D1"
|
|
|
|
|
|
# ================================================================
|
|
# Decision creation populates decision_dependencies
|
|
# ================================================================
|
|
|
|
Scenario: Decision creation records influence dependencies
|
|
Given a decision service for influence tracking
|
|
When I record a root decision "strategy_choice" for the tracked plan
|
|
And I record a child decision "implementation_choice" depending on the root decision
|
|
Then the influence edges for the tracked plan should link the root to the child
|
|
|
|
|
|
Scenario: Decision creation without dependencies records no edges
|
|
Given a decision service for influence tracking
|
|
When I record a root decision "strategy_choice" for the tracked plan
|
|
Then the influence edges for the tracked plan should be empty
|
|
|
|
|
|
# ================================================================
|
|
# Revert execution with influence edges
|
|
# ================================================================
|
|
|
|
Scenario: Revert with influence edges invalidates all affected
|
|
Given an influence-aware correction service
|
|
And a correction request targeting decision "D1" in plan "P1" for revert
|
|
And a structural tree where "D1" has children "D2"
|
|
And influence edges where "D1" influences "D3"
|
|
When I execute the revert with influence support
|
|
Then the reverted decisions should include "D1"
|
|
And the reverted decisions should include "D2"
|
|
And the reverted decisions should include "D3"
|