Files
breakpilot-compliance/ai-compliance-sdk/internal/iace/risk_matrix_test.go
T
Benjamin Admin 577ceae4e6 feat(iace): project-wide risk matrix (Severity × Probability)
Adds GET /projects/:id/risk-matrix — a confidence-aware risk view computed
on read from each hazard's category/scenario/lifecycle using the SAME model
as the GT benchmark (no persistence, so it never goes stale against the
model; the hand-defaulted iace_hazards risk columns stay untouched).

- risk_matrix.go: EstimateHazardRisk (single source of truth for S/F/W/P +
  range + level + confidence) and BuildRiskMatrix (per-hazard list + a 5×5
  Severity×Probability aggregation grid with dominant level per cell).
- Frontend: RiskMatrix grid in the Risikobewertung tab (muted colours per
  the confidence-aware tonality), level counts + tool-confidence summary,
  fed by useRiskMatrix. Shows risk for EVERY project, not only GT ones.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 08:54:47 +02:00

55 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package iace
import (
"testing"
"github.com/google/uuid"
)
func TestEstimateHazardRisk_Ordered(t *testing.T) {
r := EstimateHazardRisk([]string{"electrical_hazard"}, "Elektrischer Schlag am Gehaeuse", []string{"normal_operation"})
if r.Severity < 1 || r.Severity > 5 || r.Probability < 1 || r.Avoidance < 1 {
t.Fatalf("params out of range: %+v", r)
}
if r.RiskLow > r.RiskPoint || r.RiskPoint > r.RiskHigh {
t.Errorf("range not ordered: low=%d point=%d high=%d", r.RiskLow, r.RiskPoint, r.RiskHigh)
}
if r.Confidence != "hoch" { // "elektrisch" keyword → clear contact mode
t.Errorf("expected confidence hoch, got %q", r.Confidence)
}
}
func TestBuildRiskMatrix(t *testing.T) {
hazards := []Hazard{
{ID: uuid.New(), Name: "Elektrischer Schlag", Category: "electrical_hazard", Scenario: "Stromschlag am Gehaeuse", LifecyclePhase: "normal_operation"},
{ID: uuid.New(), Name: "Elektrischer Schlag 2", Category: "electrical_hazard", Scenario: "Stromschlag an Klemme", LifecyclePhase: "normal_operation"},
{ID: uuid.New(), Name: "Quetschen", Category: "mechanical_hazard", Scenario: "Quetschen der Hand", LifecyclePhase: "maintenance"},
}
m := BuildRiskMatrix(hazards)
if m.Total != 3 || len(m.Hazards) != 3 {
t.Fatalf("expected 3 hazards, got total=%d hazards=%d", m.Total, len(m.Hazards))
}
// The two identical electrical hazards land in the same Severity×Probability cell.
var sum int
for _, c := range m.Matrix {
sum += c.Count
if c.Severity < 1 || c.Probability < 1 {
t.Errorf("cell has invalid coords: %+v", c)
}
if c.DominantLevel == "" {
t.Errorf("cell missing dominant level: %+v", c)
}
}
if sum != 3 {
t.Errorf("matrix cell counts sum to %d, want 3", sum)
}
// Level counts must also total the hazard count.
lc := 0
for _, n := range m.LevelCounts {
lc += n
}
if lc != 3 {
t.Errorf("level counts sum to %d, want 3", lc)
}
}