From 50a9c4f458d39f5d73b6f1dda15feafa200a1580 Mon Sep 17 00:00:00 2001 From: Jan Svabenik Date: Sun, 22 Mar 2026 04:38:10 +0100 Subject: [PATCH] pipeline: weight refinement and queues by intent --- internal/pipeline/goals.go | 85 +++++++++++++++++++++++++++++++++ internal/pipeline/goals_test.go | 7 +++ internal/pipeline/scheduler.go | 7 +-- 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/internal/pipeline/goals.go b/internal/pipeline/goals.go index 3157730..7222a59 100644 --- a/internal/pipeline/goals.go +++ b/internal/pipeline/goals.go @@ -18,6 +18,7 @@ func CandidatePriorityBoost(policy Policy, hint string) float64 { boost := hintMatchBoost(policy.SignalPriorities, hint, 3.0) boost += hintMatchBoost(policy.AutoRecordClasses, hint, 1.5) boost += hintMatchBoost(policy.AutoDecodeClasses, hint, 1.0) + boost += intentHintBoost(policy.Intent, hint, 2.0) return boost } @@ -33,6 +34,7 @@ func DecisionPriorityBoost(policy Policy, hint string, class string, queue strin case "decode": boost += hintMatchBoost(policy.AutoDecodeClasses, tag, 3.0) } + boost += intentQueueBoost(policy.Intent, queue) return boost } @@ -52,3 +54,86 @@ func hintMatchBoost(values []string, hint string, weight float64) float64 { } return 0 } + +func intentHintBoost(intent string, hint string, weight float64) float64 { + tokens := intentTokens(intent) + if len(tokens) == 0 { + return 0 + } + return hintMatchBoost(tokens, hint, weight) +} + +func intentQueueBoost(intent string, queue string) float64 { + if intent == "" { + return 0 + } + intent = strings.ToLower(intent) + queue = strings.ToLower(strings.TrimSpace(queue)) + boost := 0.0 + switch queue { + case "record": + if strings.Contains(intent, "archive") || strings.Contains(intent, "record") { + boost += 2.0 + } + if strings.Contains(intent, "triage") { + boost += 1.0 + } + case "decode": + if strings.Contains(intent, "triage") { + boost += 1.5 + } + if strings.Contains(intent, "decode") || strings.Contains(intent, "analysis") || strings.Contains(intent, "classif") { + boost += 1.0 + } + } + return boost +} + +func refinementIntentWeights(intent string) (float64, float64, float64) { + if intent == "" { + return 1.0, 1.0, 1.0 + } + intent = strings.ToLower(intent) + snrWeight := 1.0 + bwWeight := 1.0 + peakWeight := 1.0 + if strings.Contains(intent, "wideband") { + bwWeight = 1.25 + } + if strings.Contains(intent, "high-density") || strings.Contains(intent, "highdensity") { + bwWeight = 1.4 + peakWeight = 1.1 + } + if strings.Contains(intent, "archive") || strings.Contains(intent, "triage") { + snrWeight = 1.15 + peakWeight = 1.1 + } + return snrWeight, bwWeight, peakWeight +} + +func intentTokens(intent string) []string { + if intent == "" { + return nil + } + fields := strings.FieldsFunc(intent, func(r rune) bool { + if r >= 'a' && r <= 'z' { + return false + } + if r >= 'A' && r <= 'Z' { + return false + } + if r >= '0' && r <= '9' { + return false + } + return true + }) + tokens := make([]string, 0, len(fields)) + for _, f := range fields { + t := strings.ToLower(strings.TrimSpace(f)) + if len(t) < 2 { + continue + } + tokens = append(tokens, t) + } + return tokens +} diff --git a/internal/pipeline/goals_test.go b/internal/pipeline/goals_test.go index cff9e90..f65db0b 100644 --- a/internal/pipeline/goals_test.go +++ b/internal/pipeline/goals_test.go @@ -17,3 +17,10 @@ func TestCandidatePriorityBoost(t *testing.T) { t.Fatalf("expected positive boost, got %v", boost) } } + +func TestCandidatePriorityBoostUsesIntent(t *testing.T) { + p := Policy{Intent: "digital-surveillance"} + if boost := CandidatePriorityBoost(p, "digital"); boost <= 0 { + t.Fatalf("expected intent boost, got %v", boost) + } +} diff --git a/internal/pipeline/scheduler.go b/internal/pipeline/scheduler.go index 725ab6b..9fbee14 100644 --- a/internal/pipeline/scheduler.go +++ b/internal/pipeline/scheduler.go @@ -23,18 +23,19 @@ func BuildRefinementPlan(candidates []Candidate, policy Policy) RefinementPlan { if len(candidates) == 0 { return plan } + snrWeight, bwWeight, peakWeight := refinementIntentWeights(policy.Intent) scored := make([]ScheduledCandidate, 0, len(candidates)) for _, c := range candidates { if c.SNRDb < policy.MinCandidateSNRDb { plan.DroppedBySNR++ continue } - priority := c.SNRDb + CandidatePriorityBoost(policy, c.Hint) + priority := c.SNRDb*snrWeight + CandidatePriorityBoost(policy, c.Hint) if c.BandwidthHz > 0 { - priority += minFloat64(c.BandwidthHz/25000.0, 6) + priority += minFloat64(c.BandwidthHz/25000.0, 6) * bwWeight } if c.PeakDb > 0 { - priority += c.PeakDb / 20.0 + priority += (c.PeakDb / 20.0) * peakWeight } scored = append(scored, ScheduledCandidate{Candidate: c, Priority: priority}) }