mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-09 16:00:59 +00:00
Purge resolved legacy alert-mirror findings on load
The previous rip retired only active "Active alert detected" findings from the now-removed detectAlertSignals -> SignalActiveAlert emitter. Resolved instances were left in place, polluting the Resolved tab and inflating the regressed total on the trust strip (a stale 8 resources each marked "regressed 3x" with descriptions like "Active warning alert: Container 'ollama' is powered off"). They have no canonical operator value -- the Alerts surface is the source of truth for currently-firing alerts -- so on load we now purge them entirely rather than keeping them around as Resolved noise. Active mirrors are still retired (auto-resolved with a clear reason) so operators see why the finding closed; resolved mirrors disappear silently because they were already in the terminal state. Idempotent. Extends TestFindingsStore_SetPersistence_RetiresLegacyAlertMirrorFindings with a fixture for the resolved-mirror case and asserts both the in-memory purge and the persisted state no longer carries it.
This commit is contained in:
parent
c3319b6304
commit
e22113230a
2 changed files with 60 additions and 15 deletions
|
|
@ -861,16 +861,31 @@ func (s *FindingsStore) SetPersistence(p FindingsPersistence) error {
|
|||
if normalizeLoadedFinding(f) {
|
||||
normalizedLoadedState = true
|
||||
}
|
||||
// One-shot retirement of legacy alert-mirror findings. The
|
||||
// One-shot cleanup of legacy alert-mirror findings. The
|
||||
// deterministic detectAlertSignals → SignalActiveAlert path
|
||||
// has been removed; any active "Active alert detected"
|
||||
// finding still persisted from an earlier build is a stale
|
||||
// mirror of an alert that already owns its own canonical
|
||||
// surface. Retire it on load with a clear reason so the
|
||||
// trust strip, regression counter, and health score stop
|
||||
// reflecting the duplicate. Idempotent — after the first
|
||||
// load with this code, no findings match the pattern.
|
||||
if isLegacyAlertMirrorFinding(f) {
|
||||
// has been removed; any "Active alert detected" finding
|
||||
// still persisted from an earlier build is a stale mirror
|
||||
// of an alert that already owns its own canonical surface.
|
||||
//
|
||||
// - Active mirrors are retired (auto-resolved with a
|
||||
// clear reason) so the trust strip, regression counter,
|
||||
// and health score stop reflecting the duplicate while
|
||||
// the operator can still see why the finding closed.
|
||||
// - Already-resolved mirrors are purged entirely. They
|
||||
// were never canonical Patrol output and have no
|
||||
// operator value in the Resolved tab; leaving them in
|
||||
// place clutters the surface and inflates the
|
||||
// "regressed" totals on the trust strip.
|
||||
//
|
||||
// Idempotent — after the first load with this code, no
|
||||
// findings match the pattern.
|
||||
if legacyAlertMirrorShape(f) {
|
||||
if f.ResolvedAt != nil {
|
||||
// Purge: do not rehydrate. The deletion is persisted
|
||||
// by the scheduleSave() call after the load loop.
|
||||
normalizedLoadedState = true
|
||||
continue
|
||||
}
|
||||
now := time.Now()
|
||||
prevLoopState := f.LoopState
|
||||
f.ResolvedAt = &now
|
||||
|
|
@ -978,15 +993,17 @@ func findingHasBogusAutoResolveCycle(f *Finding) bool {
|
|||
return hasAutoResolve
|
||||
}
|
||||
|
||||
// isLegacyAlertMirrorFinding reports whether the finding looks like an
|
||||
// active "Active alert detected" finding produced by the now-removed
|
||||
// legacyAlertMirrorShape reports whether the finding looks like an
|
||||
// "Active alert detected" finding produced by the now-removed
|
||||
// detectAlertSignals → SignalActiveAlert deterministic emitter. The title
|
||||
// is the only surface that ever produced exactly this string, so matching
|
||||
// on it is safe even without source/category checks; the additional
|
||||
// checks tighten the match to avoid retiring a hypothetical operator-
|
||||
// authored finding with the same name.
|
||||
func isLegacyAlertMirrorFinding(f *Finding) bool {
|
||||
if f == nil || f.ResolvedAt != nil {
|
||||
// checks tighten the match to avoid touching a hypothetical operator-
|
||||
// authored finding with the same name. The predicate is state-agnostic:
|
||||
// callers branch on ResolvedAt to choose between active-retirement and
|
||||
// resolved-purge behavior.
|
||||
func legacyAlertMirrorShape(f *Finding) bool {
|
||||
if f == nil {
|
||||
return false
|
||||
}
|
||||
if f.Title != "Active alert detected" {
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ func TestFindingsStore_SetPersistence_RetiresLegacyAlertMirrorFindings(t *testin
|
|||
now := time.Now()
|
||||
saved := make(chan map[string]*Finding, 1)
|
||||
|
||||
resolvedAt := now.Add(-13 * time.Hour)
|
||||
p := &recordingPersistence{
|
||||
findings: map[string]*Finding{
|
||||
// Active "Active alert detected" finding from the removed
|
||||
|
|
@ -142,6 +143,23 @@ func TestFindingsStore_SetPersistence_RetiresLegacyAlertMirrorFindings(t *testin
|
|||
Category: FindingCategoryGeneral,
|
||||
LastSeenAt: now,
|
||||
},
|
||||
// Already-resolved legacy mirror finding — must be purged
|
||||
// from the in-memory store and from disk on next save.
|
||||
// These have no canonical operator value and clutter the
|
||||
// Resolved tab / inflate the regressed totals on the trust
|
||||
// strip if left in place.
|
||||
"legacy-mirror-resolved": {
|
||||
ID: "legacy-mirror-resolved",
|
||||
Severity: FindingSeverityWarning,
|
||||
ResourceID: "vm-101",
|
||||
Title: "Active alert detected",
|
||||
Source: "ai-analysis",
|
||||
Category: FindingCategoryGeneral,
|
||||
LastSeenAt: resolvedAt,
|
||||
ResolvedAt: &resolvedAt,
|
||||
AutoResolved: true,
|
||||
RegressionCount: 3,
|
||||
},
|
||||
// Distinct finding with matching title but different source —
|
||||
// should NOT be retired (defensive: never retire something we
|
||||
// can't positively identify as the alert-mirror artifact).
|
||||
|
|
@ -199,6 +217,13 @@ func TestFindingsStore_SetPersistence_RetiresLegacyAlertMirrorFindings(t *testin
|
|||
t.Fatal("legacy mirror retirement must append an auto_resolved lifecycle event")
|
||||
}
|
||||
|
||||
// Already-resolved legacy mirror must be purged entirely. The
|
||||
// public Get path applies suppression but Get on a non-existent ID
|
||||
// returns nil; that's the contract we want.
|
||||
if got := store.Get("legacy-mirror-resolved"); got != nil {
|
||||
t.Fatalf("resolved legacy mirror must be purged from the store on load; got %+v", got)
|
||||
}
|
||||
|
||||
foreign := store.Get("foreign-title-match")
|
||||
if foreign == nil {
|
||||
t.Fatal("expected foreign-title-match to load")
|
||||
|
|
@ -220,6 +245,9 @@ func TestFindingsStore_SetPersistence_RetiresLegacyAlertMirrorFindings(t *testin
|
|||
if persisted["legacy-mirror"].ResolvedAt == nil {
|
||||
t.Fatal("retired mirror state must be persisted back")
|
||||
}
|
||||
if _, stillPersisted := persisted["legacy-mirror-resolved"]; stillPersisted {
|
||||
t.Fatal("purged resolved legacy mirror must not be persisted back to disk")
|
||||
}
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
t.Fatal("timed out waiting for retirement save")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue