save progress

This commit is contained in:
StellaOps Bot
2026-01-06 09:42:02 +02:00
parent 94d68bee8b
commit 37e11918e0
443 changed files with 85863 additions and 897 deletions

View File

@@ -0,0 +1,171 @@
# StellaOps.Policy.Determinization - Agent Guide
## Module Overview
The **Determinization** library handles CVEs that arrive without complete evidence (EPSS, VEX, reachability). It treats unknown observations as probabilistic with entropy-weighted trust that matures as evidence arrives.
**Key Concepts:**
- `ObservationState`: Lifecycle state for CVE observations (PendingDeterminization, Determined, Disputed, etc.)
- `SignalState<T>`: Null-aware wrapper distinguishing "not queried" from "queried but absent"
- `UncertaintyScore`: Knowledge completeness measurement (high entropy = missing signals)
- `ObservationDecay`: Time-based confidence decay with configurable half-life
- `GuardRails`: Monitoring requirements when allowing uncertain observations
## Directory Structure
```
src/Policy/__Libraries/StellaOps.Policy.Determinization/
├── Models/ # Core data models
│ ├── ObservationState.cs
│ ├── SignalState.cs
│ ├── SignalSnapshot.cs
│ ├── UncertaintyScore.cs
│ ├── ObservationDecay.cs
│ ├── GuardRails.cs
│ └── DeterminizationContext.cs
├── Evidence/ # Signal evidence types
│ ├── EpssEvidence.cs
│ ├── VexClaimSummary.cs
│ ├── ReachabilityEvidence.cs
│ └── ...
├── Scoring/ # Calculation services
│ ├── UncertaintyScoreCalculator.cs
│ ├── DecayedConfidenceCalculator.cs
│ ├── TrustScoreAggregator.cs
│ └── SignalWeights.cs
├── Policies/ # Policy rules (in Policy.Engine)
└── DeterminizationOptions.cs
```
## Key Patterns
### 1. SignalState<T> Usage
Always use `SignalState<T>` to wrap signal values:
```csharp
// Good - explicit status
var epss = SignalState<EpssEvidence>.WithValue(evidence, queriedAt, "first.org");
var vex = SignalState<VexClaimSummary>.Absent(queriedAt, "vendor");
var reach = SignalState<ReachabilityEvidence>.NotQueried();
var failed = SignalState<CvssEvidence>.Failed("Timeout");
// Bad - nullable without status
EpssEvidence? epss = null; // Can't tell if not queried or absent
```
### 2. Uncertainty Calculation
Entropy = 1 - (weighted present signals / max weight):
```csharp
// All signals present = 0.0 entropy (fully certain)
// No signals present = 1.0 entropy (fully uncertain)
// Formula uses configurable weights per signal type
```
### 3. Decay Calculation
Exponential decay with floor:
```csharp
decayed = max(floor, exp(-ln(2) * age_days / half_life_days))
// Default: 14-day half-life, 0.35 floor
// After 14 days: ~50% confidence
// After 28 days: ~35% confidence (floor)
```
### 4. Policy Rules
Rules evaluate in priority order (lower = first):
| Priority | Rule | Outcome |
|----------|------|---------|
| 10 | Runtime shows loaded | Escalated |
| 20 | EPSS >= threshold | Blocked |
| 25 | Proven reachable | Blocked |
| 30 | High entropy in prod | Blocked |
| 40 | Evidence stale | Deferred |
| 50 | Uncertain + non-prod | GuardedPass |
| 60 | Unreachable + confident | Pass |
| 70 | Sufficient evidence | Pass |
| 100 | Default | Deferred |
## Testing Guidelines
### Unit Tests Required
1. `SignalState<T>` factory methods
2. `UncertaintyScoreCalculator` entropy bounds [0.0, 1.0]
3. `DecayedConfidenceCalculator` half-life formula
4. Policy rule priority ordering
5. State transition logic
### Property Tests
- Entropy always in [0.0, 1.0]
- Decay monotonically decreasing with age
- Same snapshot produces same uncertainty
### Integration Tests
- DI registration with configuration
- Signal snapshot building
- Policy gate evaluation
## Configuration
```yaml
Determinization:
EpssQuarantineThreshold: 0.4
GuardedAllowScoreThreshold: 0.5
GuardedAllowEntropyThreshold: 0.4
ProductionBlockEntropyThreshold: 0.3
DecayHalfLifeDays: 14
DecayFloor: 0.35
GuardedReviewIntervalDays: 7
MaxGuardedDurationDays: 30
SignalWeights:
Vex: 0.25
Epss: 0.15
Reachability: 0.25
Runtime: 0.15
Backport: 0.10
SbomLineage: 0.10
```
## Common Pitfalls
1. **Don't confuse EntropySignal with UncertaintyScore**: `EntropySignal` measures code complexity; `UncertaintyScore` measures knowledge completeness.
2. **Always inject TimeProvider**: Never use `DateTime.UtcNow` directly for decay calculations.
3. **Normalize weights before calculation**: Call `SignalWeights.Normalize()` to ensure weights sum to 1.0.
4. **Check signal status before accessing value**: `signal.HasValue` must be true before using `signal.Value!`.
5. **Handle all ObservationStates**: Switch expressions must be exhaustive.
## Dependencies
- `StellaOps.Policy` (PolicyVerdictStatus, existing confidence models)
- `System.Collections.Immutable` (ImmutableArray for collections)
- `Microsoft.Extensions.Options` (configuration)
- `Microsoft.Extensions.Logging` (logging)
## Related Modules
- **Policy.Engine**: DeterminizationGate integrates with policy pipeline
- **Feedser**: Signal attachers emit SignalState<T>
- **VexLens**: VEX updates emit SignalUpdatedEvent
- **Graph**: CVE nodes carry ObservationState and UncertaintyScore
- **Findings**: Observation persistence and audit trail
## Sprint References
- SPRINT_20260106_001_001_LB: Core models
- SPRINT_20260106_001_002_LB: Scoring services
- SPRINT_20260106_001_003_POLICY: Policy integration
- SPRINT_20260106_001_004_BE: Backend integration
- SPRINT_20260106_001_005_FE: Frontend UI