From a61ef55d5622e0ec38edd4296ce232aa45078287 Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Sun, 6 Sep 2026 00:13:19 +0100 Subject: [PATCH] Protect recurring alert delivery after resolution and restart Resolution must retire obsolete queue rows without permanently muting a resource condition. Extend the restart/retry regression to require delivery of a new incident sharing the resolved alert ID, alongside recovery and surviving grouped alerts. Change-source: pulse-maintainer --- .../notifications/queue_resolution_retry_test.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/internal/notifications/queue_resolution_retry_test.go b/internal/notifications/queue_resolution_retry_test.go index 96cedecee..4c2cfaf7d 100644 --- a/internal/notifications/queue_resolution_retry_test.go +++ b/internal/notifications/queue_resolution_retry_test.go @@ -78,6 +78,15 @@ func TestResolvedTerminalFiringIsNotReplayedAfterRestart(t *testing.T) { if retried != 2 { t.Errorf("retried %d rows, want only surviving group and recovery", retried) } + // Alert IDs identify a resource/condition and can recur. Resolution + // must suppress the old queue row, not permanently mute that ID. + if err := q.Enqueue(&QueuedNotification{ + ID: "new-incident", Type: "webhook", Status: QueueStatusPending, + Config: []byte("{}"), MaxAttempts: 3, + Alerts: []*alerts.Alert{{ID: "healthy"}}, + }); err != nil { + t.Fatal(err) + } delivered := map[string][]string{} var mu sync.Mutex q.SetProcessor(func(n *QueuedNotification) error { @@ -104,10 +113,11 @@ func TestResolvedTerminalFiringIsNotReplayedAfterRestart(t *testing.T) { time.Sleep(time.Millisecond) } mu.Lock() - if len(delivered) != 2 || len(delivered["group"]) != 1 || + if len(delivered) != 3 || len(delivered["new-incident"]) != 1 || + delivered["new-incident"][0] != "healthy" || len(delivered["group"]) != 1 || delivered["group"][0] != "still-firing" || len(delivered["recovery"]) != 1 || delivered["recovery"][0] != "healthy" { - t.Errorf("replayed payloads = %v, want only still-firing and genuine recovery", delivered) + t.Errorf("replayed payloads = %v, want still-firing, genuine recovery and the new incident", delivered) } mu.Unlock() var failures int