Skip to content

fix: auto-resolve incidents from id-less criteria incident templates - #3425

Draft
p-paul wants to merge 2 commits into
OneUptime:masterfrom
p-paul:fix/3390-idless-incident-template-auto-resolve
Draft

p-paul wants to merge 2 commits into
OneUptime:masterfrom
p-paul:fix/3390-idless-incident-template-auto-resolve

Conversation

@p-paul

@p-paul p-paul commented Aug 27, 2026

Copy link
Copy Markdown

Title of this pull request?

fix: auto-resolve incidents from id-less criteria incident templates

Small Description?

Incidents created from id-less criteria incident templates can never auto-resolve (#3390). Both resolution paths hard-gate on createdIncidentTemplateId, which the create path leaves NULL when the template has no id — a state the write path accepts and the dedupe path explicitly supports, yet which was silently unresolvable forever.

This was previously submitted together with #3394 as one PR; it has been split so each fix can be reviewed and merged on its own. This half touches two files and carries no migration.


CriteriaIncident.id is declared required, but the write path accepts templates without one, and API- and Terraform-authored criteria routinely omit it. The create path already handles that (sets createdIncidentTemplateId only when the id is present) and so does the dedupe match, which normalises both sides to undefined. The resolution paths did not:

  • resolveSeriesIncidentsByFingerprintif (!createdCriteriaId || !createdIncidentTemplateId) { continue; }
  • shouldCloseIncident — the same gate, in both of its branches

So incidents were created correctly, deduplicated correctly, carried a correct seriesFingerprint — and stayed open forever with nothing logged to say why.

The three hard gates become one isAutoResolveIncidentTemplate() helper that normalises both sides to undefined, mirroring the dedupe path. It stays exact: an incident whose template id is NULL matches only an id-less auto-resolve template on the same criteria, never an unrelated one that carries an id. This also heals monitors already in this state, which a provider-side fix alone cannot do.


Pull Request Checklist:

  • Please make sure all jobs pass before requesting a review.
  • Put closes #XXXX in your comment to auto-close the issue that your PR fixes (if such).
  • Have you lint your code locally before submission?
  • Did you write tests where appropriate?

Related Issue?

closes #3390

Tests

IdLessIncidentTemplateAutoResolve.test.ts10 tests, all passing. Three of them fail on the pre-fix code, one per broken resolution path; the other seven pin that the fix does not over-resolve:

  • resolves an incident whose template id is NULL when the criteria opted in with an id-less template
  • still resolves an incident created from a template that does have an id
  • does not resolve a NULL-template incident when every auto-resolve template on that criteria carries an id
  • does not resolve when the creating criteria did not opt into auto-resolve at all
  • closes a NULL-template incident once its series stops breaching
  • keeps a NULL-template incident open while its series is still breaching
  • does not close a NULL-template incident when the opted-in template carries an id
  • still honours the event-driven guard for NULL-template incidents
  • closes a NULL-template incident when another criteria is now active
  • does not close a NULL-template incident when its own criteria is still active

The full Tests/Server/Utils/Monitor directory (67 suites / 1378 tests) also passes.

Scope

Two files: Common/Server/Utils/Monitor/MonitorIncident.ts and the new test. No schema change, no migration, no API surface change.

…emplates

An incident created from a criteria whose incident template has no `id`
could never be auto-resolved — not by an incoming payload reporting the
key recovered, and not by series absence.

`CriteriaIncident.id` is declared required, but the write path accepts
templates without one, and API- and Terraform-authored criteria routinely
omit it. The create path already handles that (it sets
`createdIncidentTemplateId` only when the id is present) and so does the
dedupe match, which normalises both sides to `undefined` so a created
incident still matches itself on the next cycle.

Both resolution paths did not. `resolveSeriesIncidentsByFingerprint` and
both branches of `shouldCloseIncident` returned early whenever
`createdIncidentTemplateId` was NULL, so those incidents were created
correctly, deduplicated correctly, carried a correct `seriesFingerprint`
— and then stayed open forever with nothing logged to say why.

Replace the three hard gates with one `isAutoResolveIncidentTemplate`
helper that normalises both sides to `undefined`, mirroring the dedupe
path. This stays exact: an incident whose template id is NULL matches
only an id-less auto-resolve template on the same criteria, never an
unrelated one that does carry an id. It also heals monitors already in
this state, which a provider-side fix alone cannot do.

Refs OneUptime#3390
@simlarsen

simlarsen commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

…olve

master landed its own fix for id-less incident templates while this branch
was open (`isAutoResolveConfiguredForIncident`), alongside the per-series
breaching helpers. It resolves the same bug with a looser rule: an incident
with no `createdIncidentTemplateId` is matched against its creating criteria
as a whole rather than against an id-less template entry, and a test on
master pins that behaviour.

Keep master's rule and its per-series control flow, drop this branch's
`isAutoResolveIncidentTemplate` helper, and route the two gates master did
not touch — `resolveSeriesIncidentsByFingerprint` and `shouldCloseIncident`'s
cross-criteria path, both of which still returned early on a NULL template
id — through master's helper. That is what remains of this branch: one rule,
applied on every resolution path.

Tests updated to the merged semantics.
@p-paul
p-paul marked this pull request as draft September 21, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants