Problem
PR #6591 added fingerprints to the poll-alerts Pusher payload, enabling consumers to target specific alerts instead of doing a full-table refresh. However, subscribers still cannot determine whether an alert transitioned to resolved (or any other status) without making a follow-up REST call to /alerts/query or /alerts/batch.
Since poll-alerts fires for any enrichment (new alert, ack, resolve, suppress), consumers that only care about resolution must query Keep on every single event -- even when no alert actually resolved. This adds unnecessary load on the Keep API.
Proposal
Extend the poll-alerts payload with backward-compatible, additive fields:
{
"fingerprints": ["fp-1", "fp-2"],
"alerts": [
{"fingerprint": "fp-1", "status": "resolved", "previous_status": "acknowledged"},
{"fingerprint": "fp-2", "status": "firing", "previous_status": null}
],
"statuses": {"fp-1": "resolved", "fp-2": "firing"},
"resolved_fingerprints": ["fp-1"]
}
Respects existing FINGERPRINT_PAYLOAD_LIMIT (100): if over limit, falls back to {"fingerprints": []} and omits transition fields.
How this helps downstream consumers
Event-driven retirement without extra API calls:
Downstream services (e.g. reconcilers, external webhooks, lifecycle managers) can now:
- Receive
poll-alerts event
- Check
resolved_fingerprints (or filter statuses for resolved)
- Act immediately (retire proposals, close tickets, update dashboards)
- Skip the
/alerts/query round-trip entirely
This turns a poll-then-query pattern into a pure event-driven flow -- reducing Keep API load and cutting end-to-end latency for status-aware consumers from seconds to milliseconds.
Use cases enabled:
- Reconcilers that retire pending suggestions when alerts resolve
- Webhook integrations that only care about specific transitions (e.g.
* -> resolved)
- Dashboards that track real-time status distribution without polling the REST API
- Audit systems that log state transitions with previous-status context
Implementation
See PR #6601 which implements this feature:
poll_alerts_payload() helper centralizes payload construction
- Previous status captured via batch DB query before
set_last_alert() overwrites it
- UI type widened but behavior unchanged (no breaking change for existing consumers)
- Comprehensive test coverage for payload builder and UI parser
Non-goals (potential follow-ups)
- Dedicated
alert-resolved Pusher channel (separate subscription surface)
- Filtering
poll-alerts to only fire on real transitions (currently fires on all enrichments)
- Server-side subscription filters per consumer
Problem
PR #6591 added
fingerprintsto thepoll-alertsPusher payload, enabling consumers to target specific alerts instead of doing a full-table refresh. However, subscribers still cannot determine whether an alert transitioned toresolved(or any other status) without making a follow-up REST call to/alerts/queryor/alerts/batch.Since
poll-alertsfires for any enrichment (new alert, ack, resolve, suppress), consumers that only care about resolution must query Keep on every single event -- even when no alert actually resolved. This adds unnecessary load on the Keep API.Proposal
Extend the
poll-alertspayload with backward-compatible, additive fields:{ "fingerprints": ["fp-1", "fp-2"], "alerts": [ {"fingerprint": "fp-1", "status": "resolved", "previous_status": "acknowledged"}, {"fingerprint": "fp-2", "status": "firing", "previous_status": null} ], "statuses": {"fp-1": "resolved", "fp-2": "firing"}, "resolved_fingerprints": ["fp-1"] }fingerprints-- unchanged (backward compat with feat: include fingerprints in poll-alerts payload and patch visible alert rows #6591)alerts-- per-alert transition with current and previous statusstatuses-- fingerprint-to-status map for quick lookupresolved_fingerprints-- convenience subset wherestatus == "resolved"Respects existing
FINGERPRINT_PAYLOAD_LIMIT(100): if over limit, falls back to{"fingerprints": []}and omits transition fields.How this helps downstream consumers
Event-driven retirement without extra API calls:
Downstream services (e.g. reconcilers, external webhooks, lifecycle managers) can now:
poll-alertseventresolved_fingerprints(or filterstatusesfor resolved)/alerts/queryround-trip entirelyThis turns a poll-then-query pattern into a pure event-driven flow -- reducing Keep API load and cutting end-to-end latency for status-aware consumers from seconds to milliseconds.
Use cases enabled:
* -> resolved)Implementation
See PR #6601 which implements this feature:
poll_alerts_payload()helper centralizes payload constructionset_last_alert()overwrites itNon-goals (potential follow-ups)
alert-resolvedPusher channel (separate subscription surface)poll-alertsto only fire on real transitions (currently fires on all enrichments)