save progress
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
# Sprint 20260104_001_BE - Adaptive Noise-Gating for Vulnerability Graphs
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
Implement adaptive noise-gating for vulnerability graphs to reduce alert fatigue and improve triage UX. The feature enables:
|
||||
|
||||
1. **Semantic Edge Deduplication**: Collapse redundant edges from multiple sources into single edges with provenance sets
|
||||
2. **Proof Strength Hierarchy**: Formalize evidence authority ordering (Authority > Binary > Static > Heuristic)
|
||||
3. **Stability Damping**: Prevent flip-flopping verdicts through hysteresis-based state transitions
|
||||
4. **Delta Reports**: Surface only meaningful changes with typed sections (New, Resolved, ConfidenceUp, ConfidenceDown, PolicyImpact)
|
||||
|
||||
**Working directory:** `src/__Libraries/`, `src/VexLens/`, `src/Policy/`
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- Builds on existing `VexConsensusEngine`, `PolicyGateEvaluator`, and `NoisePriorService`
|
||||
- No external dependencies; integrates with existing modules
|
||||
- Tasks can be executed in parallel across modules
|
||||
|
||||
## Documentation Prerequisites
|
||||
|
||||
- docs/README.md
|
||||
- docs/07_HIGH_LEVEL_ARCHITECTURE.md
|
||||
- docs/modules/platform/architecture-overview.md
|
||||
- CLAUDE.md (especially Section 8: Code Quality & Determinism Rules)
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | NG-001 | DONE | None | Guild | Add ProofStrength enum to StellaOps.Evidence.Core |
|
||||
| 2 | NG-002 | DONE | NG-001 | Guild | Add ProofStrength field to EvidenceRecord |
|
||||
| 3 | NG-003 | DONE | None | Guild | Create EdgeSemanticKey and deduplication logic in ReachGraph |
|
||||
| 4 | NG-004 | DONE | None | Guild | Add StabilityDampingGate to Policy.Engine.Gates |
|
||||
| 5 | NG-005 | DONE | NG-004 | Guild | Add StabilityDampingOptions with configurable thresholds |
|
||||
| 6 | NG-006 | DONE | None | Guild | Create DeltaSection enum in VexLens |
|
||||
| 7 | NG-007 | DONE | NG-006 | Guild | Extend VexDelta with section categorization |
|
||||
| 8 | NG-008 | DONE | NG-001,NG-003,NG-004,NG-006 | Guild | Create INoiseGate interface and NoiseGateService |
|
||||
| 9 | NG-009 | DONE | NG-008 | Guild | Add DI registration in VexLensServiceCollectionExtensions |
|
||||
| 10 | NG-010 | DONE | All | Guild | Add unit tests for all new components |
|
||||
| 11 | NG-011 | DONE | NG-010 | Guild | Update module AGENTS.md files |
|
||||
|
||||
## Task Details
|
||||
|
||||
### NG-001: ProofStrength Enum
|
||||
|
||||
Add `ProofStrength` enum to formalize evidence authority hierarchy:
|
||||
|
||||
```csharp
|
||||
public enum ProofStrength
|
||||
{
|
||||
Authoritative = 100, // Vendor VEX, CSAF publisher
|
||||
BinaryProof = 80, // Patch signature, binary analysis
|
||||
StaticAnalysis = 60, // Reachability, call graph
|
||||
Heuristic = 40 // Version matching, advisory correlation
|
||||
}
|
||||
```
|
||||
|
||||
Location: `src/__Libraries/StellaOps.Evidence/ProofStrength.cs`
|
||||
|
||||
### NG-002: EvidenceRecord Extension
|
||||
|
||||
Add optional `ProofStrength` field to existing evidence models for backward compatibility.
|
||||
|
||||
### NG-003: Edge Semantic Key
|
||||
|
||||
Create semantic key for edge deduplication:
|
||||
|
||||
```csharp
|
||||
public readonly record struct EdgeSemanticKey(
|
||||
string EntryPointId,
|
||||
string SinkId,
|
||||
string VulnerabilityId,
|
||||
string? GateApplied)
|
||||
{
|
||||
public string ComputeKey() =>
|
||||
$"{EntryPointId}|{SinkId}|{VulnerabilityId}|{GateApplied ?? "none"}";
|
||||
}
|
||||
```
|
||||
|
||||
Location: `src/__Libraries/StellaOps.ReachGraph/Deduplication/`
|
||||
|
||||
### NG-004: StabilityDampingGate
|
||||
|
||||
Implement hysteresis-based gate that:
|
||||
- Tracks last verdict state per (artifact, CVE) tuple
|
||||
- Requires score to persist for N hours OR change by X% before state transition
|
||||
- Prevents flip-flopping notifications
|
||||
|
||||
Location: `src/Policy/StellaOps.Policy.Engine/Gates/StabilityDampingGate.cs`
|
||||
|
||||
### NG-005: StabilityDampingOptions
|
||||
|
||||
Configuration options:
|
||||
- `MinDurationBeforeChange`: TimeSpan (default: 4 hours)
|
||||
- `MinConfidenceDeltaPercent`: double (default: 15%)
|
||||
- `EnabledStatuses`: List of VexStatus to apply damping
|
||||
|
||||
### NG-006: DeltaSection Enum
|
||||
|
||||
Categorize delta entries for UX:
|
||||
|
||||
```csharp
|
||||
public enum DeltaSection
|
||||
{
|
||||
New, // First-time finding
|
||||
Resolved, // Status changed to not_affected/fixed
|
||||
ConfidenceUp, // Confidence increased significantly
|
||||
ConfidenceDown, // Confidence decreased significantly
|
||||
PolicyImpact // Gate decision changed
|
||||
}
|
||||
```
|
||||
|
||||
### NG-007: VexDelta Extension
|
||||
|
||||
Extend existing VexDelta with section categorization and aggregate summary.
|
||||
|
||||
### NG-008: INoiseGate Interface
|
||||
|
||||
Central interface for noise-gating operations:
|
||||
|
||||
```csharp
|
||||
public interface INoiseGate
|
||||
{
|
||||
Task<IReadOnlyList<Edge>> DedupeEdgesAsync(
|
||||
IReadOnlyList<Edge> edges,
|
||||
CancellationToken ct = default);
|
||||
|
||||
Task<Verdict> ResolveNodeAsync(
|
||||
string nodeId,
|
||||
IReadOnlyList<Evidence> evidences,
|
||||
CancellationToken ct = default);
|
||||
|
||||
Task<GraphSnapshot> GateAsync(
|
||||
GraphSnapshot raw,
|
||||
CancellationToken ct = default);
|
||||
|
||||
Task<DeltaReport> DiffAsync(
|
||||
GraphSnapshot previous,
|
||||
GraphSnapshot current,
|
||||
CancellationToken ct = default);
|
||||
}
|
||||
```
|
||||
|
||||
### NG-009: DI Registration
|
||||
|
||||
Register services in `VexLensServiceCollectionExtensions`:
|
||||
|
||||
```csharp
|
||||
services.AddSingleton<INoiseGate, NoiseGateService>();
|
||||
services.AddOptions<StabilityDampingOptions>()
|
||||
.Bind(config.GetSection("NoiseGate:StabilityDamping"))
|
||||
.ValidateDataAnnotations()
|
||||
.ValidateOnStart();
|
||||
```
|
||||
|
||||
### NG-010: Unit Tests
|
||||
|
||||
Required test coverage:
|
||||
- Edge deduplication with multi-source inputs
|
||||
- Proof strength ordering in verdict resolution
|
||||
- Hysteresis behavior (flip-flop prevention)
|
||||
- Delta section categorization
|
||||
- Determinism (same inputs = same outputs)
|
||||
|
||||
### NG-011: AGENTS.md Updates
|
||||
|
||||
Update module documentation:
|
||||
- `src/VexLens/AGENTS.md`
|
||||
- `src/Policy/AGENTS.md`
|
||||
- `src/__Libraries/StellaOps.Evidence/AGENTS.md`
|
||||
|
||||
## Decisions & Risks
|
||||
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| Use ProofStrength instead of EvidenceClass | Avoids naming collision with existing EvidenceType enum |
|
||||
| Integrate with existing VexConsensusEngine | Leverages proven consensus logic rather than creating parallel infrastructure |
|
||||
| Make damping optional per-status | Production environments can enable for affected/not_affected but skip for under_investigation |
|
||||
| Store dedup metadata for audit | Provenance tracking required for transparency |
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date | Action | Notes |
|
||||
|------|--------|-------|
|
||||
| 2026-01-04 | Sprint created | Based on product advisory review |
|
||||
| 2026-01-04 | NG-001,NG-002 | Created ProofStrength enum, ProofStrengthExtensions, ProofRecord in StellaOps.Evidence.Models |
|
||||
| 2026-01-04 | NG-003 | Created EdgeSemanticKey, DeduplicatedEdge, EdgeDeduplicator in StellaOps.ReachGraph.Deduplication |
|
||||
| 2026-01-04 | NG-004,NG-005 | Created StabilityDampingGate, StabilityDampingOptions in StellaOps.Policy.Engine.Gates |
|
||||
| 2026-01-04 | NG-006,NG-007 | Created DeltaSection, DeltaEntry, DeltaReport, DeltaReportBuilder in StellaOps.VexLens.Delta |
|
||||
| 2026-01-04 | NG-008,NG-009 | Created INoiseGate, NoiseGateService, NoiseGateOptions; registered DI in VexLensServiceCollectionExtensions |
|
||||
| 2026-01-04 | NG-010 | Added StabilityDampingGateTests, NoiseGateServiceTests, DeltaReportBuilderTests |
|
||||
| 2026-01-04 | NG-011 | Updated VexLens and Policy.Engine AGENTS.md files |
|
||||
| 2026-01-04 | Sprint complete | All 11 tasks DONE |
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
# Sprint 20260104_002_FE - Noise-Gating Delta Report UI
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
Implement frontend components to display noise-gating delta reports from the VexLens backend. This sprint composes existing Angular components to minimize new code while providing a complete UI for:
|
||||
|
||||
1. **Delta Report Display**: Show changes between vulnerability graph snapshots
|
||||
2. **Section-Based Navigation**: Tabs for New, Resolved, ConfidenceUp/Down, PolicyImpact, Damped sections
|
||||
3. **Gating Statistics**: Edge deduplication rates and verdict damping metrics
|
||||
4. **Backend API Endpoints**: Expose DeltaReport via VexLens WebService
|
||||
|
||||
**Working directories:**
|
||||
- `src/Web/StellaOps.Web/src/app/` (frontend)
|
||||
- `src/VexLens/StellaOps.VexLens.WebService/` (backend API)
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- Builds on completed Sprint 20260104_001_BE (backend NoiseGate implementation)
|
||||
- Reuses existing components: `DeltaSummaryStripComponent`, `TabsComponent`, `GatingExplainerComponent`
|
||||
- Tasks NG-FE-001 through NG-FE-003 (backend + models) must complete before NG-FE-004+
|
||||
|
||||
## Existing Components to Reuse
|
||||
|
||||
| Component | Location | Usage |
|
||||
|-----------|----------|-------|
|
||||
| `DeltaSummaryStripComponent` | `features/compare/components/` | Overview stats display |
|
||||
| `TabsComponent` / `TabPanelDirective` | `shared/components/tabs/` | Section navigation |
|
||||
| `GatingExplainerComponent` | `features/triage/components/gating-explainer/` | Per-entry explanations |
|
||||
| `DeltaComputeService` patterns | `features/compare/services/` | Signal-based state management |
|
||||
| `GatingReason`, `DeltaSummary` | `features/triage/models/gating.model.ts` | Existing delta/gating types |
|
||||
| `VexStatementStatus` | `core/api/vex-hub.models.ts` | VEX status types |
|
||||
| `BadgeComponent`, `StatCardComponent` | `shared/components/` | Statistics display |
|
||||
|
||||
## Documentation Prerequisites
|
||||
|
||||
- CLAUDE.md (Section 8: Code Quality rules)
|
||||
- src/Web/StellaOps.Web/README.md
|
||||
- docs/modules/vexlens/architecture.md
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency | Task Definition |
|
||||
|---|---------|--------|----------------|-----------------|
|
||||
| 1 | NG-FE-001 | DONE | None | Add delta report API endpoints to VexLens.WebService |
|
||||
| 2 | NG-FE-002 | DONE | None | Create TypeScript models for noise-gating delta (noise-gating.models.ts) |
|
||||
| 3 | NG-FE-003 | DONE | NG-FE-002 | Create NoiseGatingApiClient service |
|
||||
| 4 | NG-FE-004 | DONE | NG-FE-003 | Create NoiseGatingSummaryStripComponent (extends DeltaSummaryStrip) |
|
||||
| 5 | NG-FE-005 | DONE | NG-FE-003 | Create DeltaEntryCardComponent for individual entries |
|
||||
| 6 | NG-FE-006 | DONE | NG-FE-004,005 | Create NoiseGatingDeltaReportComponent (container with tabs) |
|
||||
| 7 | NG-FE-007 | DONE | NG-FE-006 | Create GatingStatisticsCardComponent |
|
||||
| 8 | NG-FE-008 | DONE | NG-FE-006 | Integrate into vuln-explorer/triage workspace |
|
||||
| 9 | NG-FE-009 | DONE | All | Update feature module exports and routing |
|
||||
|
||||
## Task Details
|
||||
|
||||
### NG-FE-001: Backend API Endpoints
|
||||
|
||||
Add endpoints to `VexLensEndpointExtensions.cs`:
|
||||
|
||||
```csharp
|
||||
// Delta computation
|
||||
POST /api/v1/vexlens/deltas/compute
|
||||
Body: { fromSnapshotId, toSnapshotId, options }
|
||||
Returns: DeltaReportResponse
|
||||
|
||||
// Get gated snapshot
|
||||
GET /api/v1/vexlens/snapshots/{snapshotId}/gated
|
||||
Returns: GatedGraphSnapshotResponse
|
||||
|
||||
// Get gating statistics
|
||||
GET /api/v1/vexlens/gating/statistics
|
||||
Query: tenantId, fromDate, toDate
|
||||
Returns: GatingStatisticsResponse
|
||||
```
|
||||
|
||||
### NG-FE-002: TypeScript Models
|
||||
|
||||
Create `src/app/core/api/noise-gating.models.ts`:
|
||||
|
||||
```typescript
|
||||
// Match backend DeltaSection enum
|
||||
export type NoiseGatingDeltaSection =
|
||||
| 'new' | 'resolved' | 'confidence_up' | 'confidence_down'
|
||||
| 'policy_impact' | 'damped' | 'evidence_changed';
|
||||
|
||||
// Match backend DeltaEntry
|
||||
export interface NoiseGatingDeltaEntry {
|
||||
section: NoiseGatingDeltaSection;
|
||||
vulnerabilityId: string;
|
||||
productKey: string;
|
||||
fromStatus?: VexStatementStatus;
|
||||
toStatus?: VexStatementStatus;
|
||||
fromConfidence?: number;
|
||||
toConfidence?: number;
|
||||
justification?: string;
|
||||
rationaleClass?: string;
|
||||
summary?: string;
|
||||
contributingSources?: string[];
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
// Match backend DeltaReport
|
||||
export interface NoiseGatingDeltaReport {
|
||||
reportId: string;
|
||||
fromSnapshotDigest: string;
|
||||
toSnapshotDigest: string;
|
||||
generatedAt: string;
|
||||
entries: NoiseGatingDeltaEntry[];
|
||||
summary: NoiseGatingDeltaSummary;
|
||||
hasActionableChanges: boolean;
|
||||
}
|
||||
|
||||
// Summary counts
|
||||
export interface NoiseGatingDeltaSummary {
|
||||
totalCount: number;
|
||||
newCount: number;
|
||||
resolvedCount: number;
|
||||
confidenceUpCount: number;
|
||||
confidenceDownCount: number;
|
||||
policyImpactCount: number;
|
||||
dampedCount: number;
|
||||
evidenceChangedCount: number;
|
||||
}
|
||||
|
||||
// Gating statistics
|
||||
export interface GatingStatistics {
|
||||
originalEdgeCount: number;
|
||||
deduplicatedEdgeCount: number;
|
||||
edgeReductionPercent: number;
|
||||
totalVerdictCount: number;
|
||||
surfacedVerdictCount: number;
|
||||
dampedVerdictCount: number;
|
||||
duration: string;
|
||||
}
|
||||
```
|
||||
|
||||
### NG-FE-003: API Client
|
||||
|
||||
Create `src/app/core/api/noise-gating.client.ts`:
|
||||
|
||||
```typescript
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class NoiseGatingApiClient {
|
||||
// Follow VexHubApiHttpClient patterns
|
||||
// Signal-based state management
|
||||
// Caching with Map<string, Observable>
|
||||
}
|
||||
```
|
||||
|
||||
### NG-FE-004: Summary Strip Component
|
||||
|
||||
Extend `DeltaSummaryStripComponent` pattern for noise-gating sections:
|
||||
- New (green), Resolved (blue), ConfidenceUp (teal), ConfidenceDown (orange)
|
||||
- PolicyImpact (red), Damped (gray), EvidenceChanged (purple)
|
||||
|
||||
### NG-FE-005: Delta Entry Card
|
||||
|
||||
Create `delta-entry-card.component.ts`:
|
||||
- Display CVE ID, package, status transition
|
||||
- Confidence change visualization (before -> after with delta %)
|
||||
- Section-specific styling
|
||||
- Link to GatingExplainerComponent for details
|
||||
|
||||
### NG-FE-006: Container Component
|
||||
|
||||
Create `noise-gating-delta-report.component.ts`:
|
||||
- Uses `TabsComponent` with section tabs (badge counts)
|
||||
- Uses `NoiseGatingSummaryStripComponent` for overview
|
||||
- Filterable entry list within each tab
|
||||
- Follows three-pane pattern from compare feature
|
||||
|
||||
### NG-FE-007: Statistics Card
|
||||
|
||||
Create `gating-statistics-card.component.ts`:
|
||||
- Edge reduction percentage visualization
|
||||
- Verdict surfacing/damping ratios
|
||||
- Processing duration display
|
||||
- Follows `StatCardComponent` patterns
|
||||
|
||||
### NG-FE-008: Triage Integration
|
||||
|
||||
Add to vuln-explorer:
|
||||
- "Delta Report" tab or drawer
|
||||
- Trigger from snapshot comparison
|
||||
- Link from finding detail to delta context
|
||||
|
||||
### NG-FE-009: Module Exports
|
||||
|
||||
Update feature module:
|
||||
- Export new components
|
||||
- Add to routing if needed
|
||||
- Register API client
|
||||
|
||||
## Decisions & Risks
|
||||
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| Compose existing components | ~70% code reuse, consistent UX |
|
||||
| Signal-based state | Matches existing Angular 17 patterns |
|
||||
| Section tabs vs flat list | Better UX for categorized changes |
|
||||
| Lazy-load delta data | Large reports should not block initial render |
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date | Action | Notes |
|
||||
|------|--------|-------|
|
||||
| 2026-01-04 | Sprint created | Based on backend noise-gating completion |
|
||||
| 2026-01-04 | NG-FE-001 | Added endpoints to VexLensEndpointExtensions.cs, created NoiseGatingApiModels.cs |
|
||||
| 2026-01-04 | NG-FE-001 | Created ISnapshotStore, IGatingStatisticsStore with in-memory implementations |
|
||||
| 2026-01-04 | NG-FE-001 | Updated INoiseGate.DiffAsync to accept DeltaReportOptions |
|
||||
| 2026-01-04 | NG-FE-001 | Registered storage services in VexLensServiceCollectionExtensions |
|
||||
| 2026-01-04 | NG-FE-002 | Created noise-gating.models.ts with all API types and helper functions |
|
||||
| 2026-01-04 | NG-FE-003 | Created noise-gating.client.ts with signal-based state and caching |
|
||||
| 2026-01-04 | NG-FE-004 | Created NoiseGatingSummaryStripComponent with section badges |
|
||||
| 2026-01-04 | NG-FE-005 | Created DeltaEntryCardComponent for individual entries |
|
||||
| 2026-01-04 | NG-FE-006 | Created NoiseGatingDeltaReportComponent container with tabs |
|
||||
| 2026-01-04 | NG-FE-007 | Created GatingStatisticsCardComponent with progress bars |
|
||||
| 2026-01-04 | NG-FE-009 | Created index.ts barrel export for noise-gating components |
|
||||
| 2026-01-04 | NG-FE-008 | Integrated noise-gating into TriageCanvasComponent with Delta tab |
|
||||
| 2026-01-04 | NG-FE-008 | Added keyboard shortcut 'd' for delta tab |
|
||||
| 2026-01-04 | NG-FE-008 | Updated triage components index.ts to export noise-gating components |
|
||||
| 2026-01-04 | Sprint complete | All 9 tasks completed |
|
||||
|
||||
Reference in New Issue
Block a user