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.
This commit is contained in:
rcourtman 2025-12-21 12:41:27 +00:00
parent 98f3d0d48f
commit 367d22e937
2 changed files with 22 additions and 4 deletions

View file

@ -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*/, '');

View file

@ -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