From 68c75d83ea32f33dc662d2319d7df0522c2026ad Mon Sep 17 00:00:00 2001 From: Jan Svabenik Date: Sun, 22 Mar 2026 10:31:33 +0100 Subject: [PATCH] Add level role governance tests --- cmd/sdrd/pipeline_runtime_test.go | 7 +++ internal/pipeline/evidence_test.go | 45 +++++++++++++++++++ internal/pipeline/scheduler_test.go | 6 +-- internal/pipeline/surveillance_policy_test.go | 30 +++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 internal/pipeline/evidence_test.go create mode 100644 internal/pipeline/surveillance_policy_test.go diff --git a/cmd/sdrd/pipeline_runtime_test.go b/cmd/sdrd/pipeline_runtime_test.go index cb0fa3b..99e2654 100644 --- a/cmd/sdrd/pipeline_runtime_test.go +++ b/cmd/sdrd/pipeline_runtime_test.go @@ -53,7 +53,11 @@ func TestSurveillanceLevelsRespectStrategy(t *testing.T) { if len(plan.Levels) != 1 { t.Fatalf("expected single level for single-resolution, got %d", len(plan.Levels)) } + if plan.Levels[0].Role != pipeline.RoleSurveillancePrimary { + t.Fatalf("expected primary role, got %q", plan.Levels[0].Role) + } policy.SurveillanceStrategy = "multi-res" + policy.Intent = "wideband-surveillance" plan = rt.buildSurveillancePlan(policy) if len(plan.Levels) != 2 { t.Fatalf("expected secondary level for multi-res, got %d", len(plan.Levels)) @@ -61,6 +65,9 @@ func TestSurveillanceLevelsRespectStrategy(t *testing.T) { if plan.Levels[1].Decimation != 2 { t.Fatalf("expected decimation factor 2, got %d", plan.Levels[1].Decimation) } + if plan.Levels[1].Role != pipeline.RoleSurveillanceDerived { + t.Fatalf("expected derived role, got %q", plan.Levels[1].Role) + } } func TestWindowSpanBounds(t *testing.T) { diff --git a/internal/pipeline/evidence_test.go b/internal/pipeline/evidence_test.go new file mode 100644 index 0000000..62873a2 --- /dev/null +++ b/internal/pipeline/evidence_test.go @@ -0,0 +1,45 @@ +package pipeline + +import "testing" + +func TestLevelRoleClassification(t *testing.T) { + primary := AnalysisLevel{Name: "surveillance", Role: RoleSurveillancePrimary, Truth: "surveillance"} + derived := AnalysisLevel{Name: "surveillance-lowres", Role: RoleSurveillanceDerived, Truth: "surveillance"} + support := AnalysisLevel{Name: "surveillance-lowres", Role: RoleSurveillanceSupport, Truth: "surveillance"} + presentation := AnalysisLevel{Name: "presentation", Role: RolePresentation, Truth: "presentation"} + + if !IsDetectionLevel(primary) || IsPresentationLevel(primary) || IsSupportLevel(primary) { + t.Fatalf("primary role classification failed: %+v", primary) + } + if !IsDetectionLevel(derived) || IsPresentationLevel(derived) || IsSupportLevel(derived) { + t.Fatalf("derived role classification failed: %+v", derived) + } + if IsDetectionLevel(support) || IsPresentationLevel(support) || !IsSupportLevel(support) { + t.Fatalf("support role classification failed: %+v", support) + } + if IsDetectionLevel(presentation) || !IsPresentationLevel(presentation) || IsSupportLevel(presentation) { + t.Fatalf("presentation role classification failed: %+v", presentation) + } +} + +func TestCandidateEvidenceStateTracksSupportLevels(t *testing.T) { + candidate := Candidate{ + ID: 1, + Evidence: []LevelEvidence{ + {Level: AnalysisLevel{Name: "surveillance", Role: RoleSurveillancePrimary, Truth: "surveillance"}, Provenance: "primary"}, + {Level: AnalysisLevel{Name: "surveillance-lowres", Role: RoleSurveillanceDerived, Truth: "surveillance"}, Provenance: "derived"}, + {Level: AnalysisLevel{Name: "surveillance-support", Role: RoleSurveillanceSupport, Truth: "surveillance"}, Provenance: "support"}, + {Level: AnalysisLevel{Name: "presentation", Role: RolePresentation, Truth: "presentation"}, Provenance: "display"}, + }, + } + state := CandidateEvidenceStateFor(candidate) + if state.DetectionLevelCount != 2 || state.PrimaryLevelCount != 1 || state.DerivedLevelCount != 1 { + t.Fatalf("unexpected detection counts: %+v", state) + } + if state.SupportLevelCount != 1 || state.PresentationLevelCount != 1 { + t.Fatalf("unexpected support/presentation counts: %+v", state) + } + if !state.MultiLevelConfirmed || state.DerivedOnly { + t.Fatalf("unexpected confirmation flags: %+v", state) + } +} diff --git a/internal/pipeline/scheduler_test.go b/internal/pipeline/scheduler_test.go index 38834f8..7843423 100644 --- a/internal/pipeline/scheduler_test.go +++ b/internal/pipeline/scheduler_test.go @@ -185,7 +185,7 @@ func TestScheduleCandidatesDerivedOnlyPenalty(t *testing.T) { SNRDb: 10, BandwidthHz: 12000, Evidence: []LevelEvidence{ - {Level: AnalysisLevel{Name: "surveillance", Role: "surveillance", Truth: "surveillance"}}, + {Level: AnalysisLevel{Name: "surveillance", Role: RoleSurveillancePrimary, Truth: "surveillance"}}, }, } derived := Candidate{ @@ -193,7 +193,7 @@ func TestScheduleCandidatesDerivedOnlyPenalty(t *testing.T) { SNRDb: 10, BandwidthHz: 12000, Evidence: []LevelEvidence{ - {Level: AnalysisLevel{Name: "surveillance-lowres", Role: "surveillance-lowres", Truth: "surveillance"}}, + {Level: AnalysisLevel{Name: "surveillance-lowres", Role: RoleSurveillanceDerived, Truth: "surveillance"}}, }, } plan := BuildRefinementPlan([]Candidate{derived, primary}, policy) @@ -211,7 +211,7 @@ func TestScheduleCandidatesDerivedOnlyStrategyBias(t *testing.T) { SNRDb: 9, BandwidthHz: 12000, Evidence: []LevelEvidence{ - {Level: AnalysisLevel{Name: "surveillance-lowres", Role: "surveillance-lowres", Truth: "surveillance"}}, + {Level: AnalysisLevel{Name: "surveillance-lowres", Role: RoleSurveillanceDerived, Truth: "surveillance"}}, }, } singlePlan := BuildRefinementPlan([]Candidate{cand}, Policy{MinCandidateSNRDb: 0}) diff --git a/internal/pipeline/surveillance_policy_test.go b/internal/pipeline/surveillance_policy_test.go new file mode 100644 index 0000000..552735e --- /dev/null +++ b/internal/pipeline/surveillance_policy_test.go @@ -0,0 +1,30 @@ +package pipeline + +import "testing" + +func TestSurveillanceDetectionPolicyAuto(t *testing.T) { + policy := Policy{ + Mode: "wideband-balanced", + Profile: "wideband-balanced", + Intent: "wideband-surveillance", + SurveillanceStrategy: "multi-resolution", + } + policy.SurveillanceDerivedDetection = "auto" + got := SurveillanceDetectionPolicyFromPolicy(policy) + if !got.DerivedDetectionEnabled { + t.Fatalf("expected auto policy to enable derived detection, got %+v", got) + } + + policy.Profile = "archive" + policy.Intent = "archive-and-triage" + got = SurveillanceDetectionPolicyFromPolicy(policy) + if got.DerivedDetectionEnabled { + t.Fatalf("expected archive policy to disable derived detection, got %+v", got) + } + + policy = Policy{SurveillanceStrategy: "single-resolution", SurveillanceDerivedDetection: "auto"} + got = SurveillanceDetectionPolicyFromPolicy(policy) + if got.DerivedDetectionEnabled { + t.Fatalf("expected single-resolution to disable derived detection, got %+v", got) + } +}