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