# Counterfactual Engine (Policy Diff Analysis) ## Module Policy ## Status VERIFIED ## Description Counterfactual engine that computes the difference between current and proposed policy configurations to show what would change. ## Implementation Details - **CounterfactualEngine**: `src/Policy/__Libraries/StellaOps.Policy/Counterfactuals/CounterfactualEngine.cs` -- `CounterfactualEngine` (sealed class implements `ICounterfactualEngine`) - `ComputeAsync(finding, verdict, document, scoringConfig, options?, ct)` computes counterfactual paths for a blocked finding - Returns `CounterfactualResult` with paths to pass when finding is currently blocked - Returns `AlreadyPassing` result when finding already has Pass verdict - Five counterfactual path types: - **VEX path**: simulates finding with `not_affected` VEX status; skipped if already not_affected - **Exception path**: computes exception effort based on severity (Critical=5, High=4, Medium=3, Low=2) - **Reachability path**: simulates finding with `reachability:no`; effort varies (2 if unknown, 4 if currently reachable) - **Version upgrade path**: uses `FixedVersionLookup` delegate to find fixed version; extracts current version from PURL - **Compensating control path**: suggests compensating controls (effort=4) - VEX and reachability paths use `PolicyEvaluation.EvaluateFinding` to simulate what-if verdicts - Tag-based signals: reads `vex:` and `reachability:` prefixed tags from finding - **CounterfactualOptions**: `src/Policy/__Libraries/StellaOps.Policy/Counterfactuals/CounterfactualEngine.cs` -- options record - `IncludeVexPaths`, `IncludeExceptionPaths`, `IncludeReachabilityPaths`, `IncludeVersionUpgradePaths`, `IncludeCompensatingControlPaths` (all default true) - `PolicyAllowsExceptions`, `PolicyConsidersReachability`, `PolicyAllowsCompensatingControls` (all default true) - `FixedVersionLookup` -- async delegate `(cve, purl, ct) => fixedVersion?` for version upgrade lookup - **CounterfactualResult**: `src/Policy/__Libraries/StellaOps.Policy/Counterfactuals/CounterfactualResult.cs` -- result model with finding ID and list of `CounterfactualPath` - **CounterfactualPath**: paths with type, description, and effort rating - Factory methods: `Vex(currentStatus, cve, effort)`, `Exception(cve, effort)`, `Reachability(current, findingId, effort)`, `VersionUpgrade(current, fixed, purl, effort)`, `CompensatingControl(findingId, effort)` ## E2E Test Plan - [x] Compute counterfactuals for a blocked finding with VEX status=affected; verify VEX path suggests not_affected and simulated verdict would pass - [x] Compute counterfactuals for a finding already passing; verify AlreadyPassing result with no paths - [x] Compute counterfactuals with IncludeVexPaths=false; verify no VEX path in result - [x] Compute counterfactuals for a finding with reachability=unknown; verify reachability path with effort=2 - [x] Compute counterfactuals for a finding with reachability=yes; verify reachability path with effort=4 - [x] Compute counterfactuals with FixedVersionLookup providing a fixed version; verify version upgrade path with current and fixed versions - [x] Compute counterfactuals with FixedVersionLookup returning null; verify no version upgrade path - [x] Verify exception path effort: Critical finding has effort=5, Low finding has effort=2 - [x] Compute counterfactuals with PolicyAllowsExceptions=false; verify no exception path - [x] Verify all five path types are present when all options are enabled and applicable ## Verification - **Run ID**: run-001 - **Date**: 2026-02-12 - **Tier 0**: PASS - Both source files exist (CounterfactualEngine.cs, CounterfactualResult.cs) with non-trivial implementation - **Tier 1**: PASS - Build succeeds, 781 tests pass - **Tier 2**: PASS - 22 new behavioral tests written covering all 5 counterfactual path types, options control, effort scaling, null validation, result sorting, and factory methods - **New test file**: `src/Policy/__Tests/StellaOps.Policy.Tests/Counterfactuals/CounterfactualEngineTests.cs`