[ING-502] feat(alerts): add alert resolution columns - #6080
Merged
Conversation
aquinofb
requested review from
a team,
mariohd and
toommz
and removed request for
a team
August 5, 2026 13:42
toommz
approved these changes
Aug 5, 2026
aquinofb
force-pushed
the
ing-502-alert-resolution-columns
branch
2 times, most recently
from
August 6, 2026 13:26
790ae06 to
6765a55
Compare
Lago alerts only signal when usage or a wallet balance crosses a limit; they never signal the return to normal. Customers who block something automatically on an alert have no automatic way to release that block. The Alert Resolution feature adds an alert.resolved webhook that a threshold can opt into, and this is its first step: the schema every later part of the feature needs. Nothing here is reachable by a customer. The feature stays inactive until the API opt-in ships, so this lands purely as groundwork. Alert thresholds gain notify_on, recording which transitions should notify. It defaults to notifying on trigger only, so existing alerts behave exactly as they do today. The alert events table gains a kind, distinguishing a real trigger from a recovery and from a silent record written when a threshold is already past its line at opt-in time. It also gains the two fields a recovery needs: which opted-in thresholds remain in alarm after the event, and whether the alert is fully back to normal across all of its thresholds. Both are nullable because only recovery rows carry them. Every column is added with a constant default, so on PostgreSQL 15 these are metadata-only changes with no table rewrite and no long lock, and no back-fill is required. The three triggered_alerts associations are scoped to triggers only, so that readers whose name already promises triggers keep meaning that once recoveries exist. This is deliberately done now, while every row is a trigger and the scope is verifiably a no-op, rather than later when it would be a behaviour change entangled with the recovery engine. Alert also gains all_triggered_alerts for the full event stream, following the same pattern as billing_entities and all_billing_entities on Organization, since the recovery engine needs to read non-trigger rows.
aquinofb
force-pushed
the
ing-502-alert-resolution-columns
branch
from
August 6, 2026 14:01
6765a55 to
9d5b1df
Compare
mariohd
approved these changes
Aug 6, 2026
aquinofb
added a commit
that referenced
this pull request
Aug 12, 2026
…t view (#6083) > Stacked on #6080, which adds the column this filters on. GitHub will retarget this to `main` once that merges. ## Context The alert events export view selects every row of the events table with no filter. That table now also holds recovery events and silent seed records, and the view exposes no column that would let a consumer tell them apart, so without a filter they arrive downstream indistinguishable from alerts that actually fired: ```mermaid graph LR T["kind: triggered<br/>a real alert firing"] --> V1["view v01<br/>no filter"] R["kind: resolved<br/>a recovery"] --> V1 S["kind: seeded<br/>silent record, no webhook"] --> V1 V1 --> W1["consumer sees all three,<br/>indistinguishable"] T2["kind: triggered"] --> V2["view v02<br/>WHERE kind = triggered"] R2["kind: resolved"] -.blocked.-> V2 S2["kind: seeded"] -.blocked.-> V2 V2 --> W2["consumer sees<br/>real firings only"] ``` ## Changes Ships a new version of the view restricted to real triggers. The column list is unchanged, so nothing a consumer already reads moves or disappears; only rows that were never meant to be there are excluded. An export of recovery events can follow separately if anyone needs one. Plain equality is used rather than `IS DISTINCT FROM`. #5905 needed the latter on `exports_fees_v03`, because that view joins to invoices so the column is NULL for legitimate rows, but here the discriminator is NOT NULL on the base table and the view has no join. Adds the view's first spec: a trigger is exported, a recovery and a seed record are not. ## Note for consumers of this view This removes rows that would otherwise be emitted, so anything counting rows from this view will see real firings only. Worth agreeing with the people reading it before this merges rather than after.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Lago alerts only fire when usage or a wallet balance crosses a limit; they never signal the return to normal. A customer who automatically blocks something on an alert has no automatic way to release that block. This adds the schema for a new
alert.resolvedwebhook that a threshold can opt into.Nothing here is reachable yet. The feature stays inactive until the API opt-in ships, so this is groundwork.
Changes
notify_onon alert thresholds. It defaults to notifying on trigger only, so existing alerts behave exactly as today.kindon alert events, distinguishing a real trigger from a recovery, and from a silent record written when a threshold already sits past its line at opt-in time.in_alarm_thresholdsandfully_resolvedon alert events, populated only on recovery rows.triggered_alertsassociations are scoped to triggers, so readers whose name already promises triggers keep meaning that once recoveries exist.Alertalso gainsall_triggered_alertsfor the full event stream, mirroringbilling_entitiesandall_billing_entitiesonOrganization.Every column is added with a constant default, so these are metadata-only changes on PostgreSQL 15: no table rewrite, no long lock, and no back-fill.
Both alert serializers, the GraphQL threshold type and the export view all enumerate their fields explicitly, so none of the new columns reaches a customer-visible surface.