Phase 2 follow-up.
saas_incidents.sla_due_at is populated on create from organizations.default_sla_hours but nothing reacts when it lapses; the FE shows the timestamp but no operator-visible 'breached' signal fires.
Scope
- New worker tick (or extend an existing one) that selects incidents where
sla_due_at < NOW() AND status IN ('OPEN','INVESTIGATING') AND no SLA_BREACHED timeline event yet.
- For each, write a
SLA_BREACHED timeline event (new SaasIncidentTimelineKind value) and update last_activity_at.
- Optional: send a notification via the existing notifications path (Slack / email) for high-severity SLA breaches.
- Add a 'SLA breach' badge on the incident list and a banner on the detail page when
sla_due_at is in the past and the incident is unresolved.
- Audit log row per breach event.
Acceptance
- Worker is idempotent (re-running the tick does not emit duplicate events).
- Tests cover the selection predicate, idempotency, and the FE badge logic.
- Tenant isolation: the worker iterates per organization.
Phase 2 follow-up.
saas_incidents.sla_due_atis populated on create fromorganizations.default_sla_hoursbut nothing reacts when it lapses; the FE shows the timestamp but no operator-visible 'breached' signal fires.Scope
sla_due_at < NOW()ANDstatus IN ('OPEN','INVESTIGATING')AND noSLA_BREACHEDtimeline event yet.SLA_BREACHEDtimeline event (newSaasIncidentTimelineKindvalue) and updatelast_activity_at.sla_due_atis in the past and the incident is unresolved.Acceptance