fix(ai): filter out noise from anomalies and status changes
Critical changes to surface only actionable insights: 1. Anomalies now require at least 50% deviation from baseline - '1.0x baseline' values filtered out (statistically significant but not actionable) - Must be >1.5x above OR <0.5x below baseline to report 2. Status changes filter out startup noise - 'unknown → running' is just system starting, not a real state change - Backups removed from main list (they have dedicated section) 3. Only show genuinely interesting changes: - Config changes, migrations, restarts, deletions - Things that require operator attention This massively reduces noise while keeping high-signal alerts.
This commit is contained in:
parent
5138b01ed8
commit
0f22906767
2 changed files with 31 additions and 16 deletions
|
|
@ -291,14 +291,22 @@ export const AIOverviewTable: Component<{ showWhenEmpty?: boolean }> = (props) =
|
|||
}
|
||||
|
||||
|
||||
// Changes - only show meaningful changes, not just "created" (infrastructure detection)
|
||||
// Valuable changes: config, status, migrated, restarted, deleted, backed_up
|
||||
// Skip: created (just means AI patrol discovered the resource)
|
||||
const meaningfulChanges = changes().filter(c => c.change_type !== 'created');
|
||||
// Changes - only show meaningful changes, not noise
|
||||
// Skip: created (just patrol discovering resources)
|
||||
// Skip: backed_up (backups have their own section, no need to duplicate here)
|
||||
// Skip: status changes from "unknown" (just startup, not real state changes)
|
||||
const meaningfulChanges = changes().filter(c => {
|
||||
if (c.change_type === 'created') return false;
|
||||
if (c.change_type === 'backed_up') return false;
|
||||
// Filter out startup noise: "unknown → running" or "unknown → stopped"
|
||||
if (c.change_type === 'status' && c.description?.includes('unknown →')) return false;
|
||||
return true;
|
||||
});
|
||||
const visibleChanges = showAllChanges()
|
||||
? meaningfulChanges
|
||||
: meaningfulChanges.slice(0, CHANGE_LIMIT);
|
||||
|
||||
|
||||
for (const change of visibleChanges) {
|
||||
const changeTypeBadgeClass: Record<string, string> = {
|
||||
deleted: 'bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300',
|
||||
|
|
|
|||
|
|
@ -291,33 +291,40 @@ func (s *Store) CheckResourceAnomalies(resourceID string, metrics map[string]flo
|
|||
|
||||
for metric, value := range metrics {
|
||||
severity, zScore, baseline := s.CheckAnomaly(resourceID, metric, value)
|
||||
if severity != AnomalyNone {
|
||||
if severity != AnomalyNone && baseline != nil {
|
||||
// Compute ratio: current value / baseline mean
|
||||
ratio := value / baseline.Mean
|
||||
|
||||
// Filter out statistically significant but practically meaningless anomalies
|
||||
// Users don't care about "1.0x baseline" or small deviations
|
||||
// Require at least 50% deviation from baseline to report
|
||||
if ratio >= 0.5 && ratio <= 1.5 {
|
||||
continue // Too close to baseline to be actionable
|
||||
}
|
||||
|
||||
report := AnomalyReport{
|
||||
ResourceID: resourceID,
|
||||
Metric: metric,
|
||||
CurrentValue: value,
|
||||
ZScore: zScore,
|
||||
Severity: severity,
|
||||
BaselineMean: baseline.Mean,
|
||||
BaselineStdDev: baseline.StdDev,
|
||||
}
|
||||
|
||||
if baseline != nil {
|
||||
report.BaselineMean = baseline.Mean
|
||||
report.BaselineStdDev = baseline.StdDev
|
||||
|
||||
// Generate human-readable description
|
||||
ratio := value / baseline.Mean
|
||||
direction := "above"
|
||||
if zScore < 0 {
|
||||
direction = "below"
|
||||
}
|
||||
report.Description = formatAnomalyDescription(metric, ratio, direction, severity)
|
||||
// Generate human-readable description
|
||||
direction := "above"
|
||||
if zScore < 0 {
|
||||
direction = "below"
|
||||
}
|
||||
report.Description = formatAnomalyDescription(metric, ratio, direction, severity)
|
||||
|
||||
anomalies = append(anomalies, report)
|
||||
}
|
||||
}
|
||||
|
||||
return anomalies
|
||||
|
||||
}
|
||||
|
||||
// formatAnomalyDescription generates a human-readable anomaly description
|
||||
|
|
|
|||
Loading…
Reference in a new issue