From 367d22e937bef7dbd3c3484f490454a4f8b83d9f Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sun, 21 Dec 2025 12:41:27 +0000 Subject: [PATCH] fix(ai): filter out noise from AI intelligence display Critical fixes to show only actionable insights: 1. Skip stopped VMs/containers from anomaly detection - '0.0x baseline' for stopped resources is expected, not an anomaly - Only check anomalies for status='running' 2. Filter correlations by confidence (>=70%) - Low confidence correlations are likely coincidental - Only show high-confidence, actionable dependencies This reduces noise and surfaces genuinely useful intelligence. --- .../src/components/shared/AIOverviewTable.tsx | 14 ++++++++++---- internal/api/ai_intelligence_handlers.go | 12 ++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/frontend-modern/src/components/shared/AIOverviewTable.tsx b/frontend-modern/src/components/shared/AIOverviewTable.tsx index c4c5e80..c293215 100644 --- a/frontend-modern/src/components/shared/AIOverviewTable.tsx +++ b/frontend-modern/src/components/shared/AIOverviewTable.tsx @@ -211,12 +211,16 @@ export const AIOverviewTable: Component<{ showWhenEmpty?: boolean }> = (props) = }); } - // Correlations - sorted by confidence, limited unless expanded - const sortedCorrelations = [...correlations()].sort((a, b) => b.confidence - a.confidence); + // Correlations - only show high-confidence (>=70%) to avoid noise + // Low confidence correlations are likely coincidental and not actionable + const MIN_CORRELATION_CONFIDENCE = 0.70; + const highConfidenceCorrelations = correlations().filter(c => c.confidence >= MIN_CORRELATION_CONFIDENCE); + const sortedCorrelations = [...highConfidenceCorrelations].sort((a, b) => b.confidence - a.confidence); const visibleCorrelations = showAllDependencies() ? sortedCorrelations : sortedCorrelations.slice(0, DEPENDENCY_LIMIT); + for (const corr of visibleCorrelations) { rows.push({ id: `corr-${corr.source_id}-${corr.target_id}`, @@ -560,9 +564,11 @@ export const AIOverviewTable: Component<{ showWhenEmpty?: boolean }> = (props) = // Calculate hidden items per section const hiddenDependencies = () => { - const total = correlations().length; - return showAllDependencies() ? 0 : Math.max(0, total - DEPENDENCY_LIMIT); + // Only count high-confidence correlations (>=70%) + const highConfidence = correlations().filter(c => c.confidence >= 0.70); + return showAllDependencies() ? 0 : Math.max(0, highConfidence.length - DEPENDENCY_LIMIT); }; + const hiddenActions = () => { const actionable = remediations().filter(rem => { const cmd = rem.action.trim().replace(/^\[[^\]]+\]\s*/, ''); diff --git a/internal/api/ai_intelligence_handlers.go b/internal/api/ai_intelligence_handlers.go index e03c7c0..d8dd1e9 100644 --- a/internal/api/ai_intelligence_handlers.go +++ b/internal/api/ai_intelligence_handlers.go @@ -604,6 +604,11 @@ func (h *AISettingsHandler) HandleGetAnomalies(w http.ResponseWriter, r *http.Re continue // Skip templates } + // Skip VMs that aren't running - stopped VMs with 0% usage is expected, not an anomaly + if vm.Status != "running" { + continue + } + // Skip if we don't have baselines for this resource if _, ok := resourceMetrics[vm.ID]; !ok { if resourceID == "" { @@ -613,6 +618,7 @@ func (h *AISettingsHandler) HandleGetAnomalies(w http.ResponseWriter, r *http.Re continue } } + metrics := map[string]float64{ "cpu": vm.CPU * 100, // CPU is already 0-1, convert to percentage @@ -648,6 +654,11 @@ func (h *AISettingsHandler) HandleGetAnomalies(w http.ResponseWriter, r *http.Re continue // Skip templates } + // Skip containers that aren't running - stopped containers with 0% usage is expected, not an anomaly + if ct.Status != "running" { + continue + } + // Skip if we don't have baselines for this resource if _, ok := resourceMetrics[ct.ID]; !ok { if resourceID == "" { @@ -657,6 +668,7 @@ func (h *AISettingsHandler) HandleGetAnomalies(w http.ResponseWriter, r *http.Re continue } } + metrics := map[string]float64{ "cpu": ct.CPU * 100, // CPU is already 0-1, convert to percentage