package notify import ( "io" "log" "testing" ) // R-70/R-71c severity contract, alongside the v0.71.0 guards: the two new detector events carry // `warning` — they route to the OPERATOR through the existing severity gate, with NO widening of // severityNotifies and NO customer email (neither type is in any default enabled_events set, and // neither has a customerMessages entry — operator-only until the mechanism has history). func TestOffsiteDeliveryEvents_WarningRoutesToOperatorOnly(t *testing.T) { st := newDispStore(t) d := NewDispatcher(st, "test-key", "hub@felhom.eu", "op@felhom.eu", true, log.New(io.Discard, "", 0)) mails := captureSeam(d) d.ProcessEvent("c1", "offsite_delivery_stuck", "warning", "stuck", "{}", "hub") d.ProcessEvent("c1", "offsite_credential_restaged", "warning", "restaged", "{}", "hub") op := mailsFor(*mails, "op@felhom.eu") if len(op) != 2 { t.Fatalf("operator mails = %d, want 2 (warning must notify the operator)", len(op)) } // customer leg: c1 has no notification prefs row → nothing may go anywhere else if len(*mails) != 2 { t.Fatalf("total mails = %d, want 2 — the detector events are operator-only", len(*mails)) } } // The deliberate decision, as an explicit test beside TestRecovery_SeverityStaysInfo: had these // events shipped as `info`, the dispatcher would silently drop them — the exact invisibility R-70 // exists to kill. This pins the severity choice against a future "quiet them down" edit. func TestOffsiteDeliveryEvents_InfoWouldBeSilent(t *testing.T) { st := newDispStore(t) d := NewDispatcher(st, "test-key", "hub@felhom.eu", "op@felhom.eu", true, log.New(io.Discard, "", 0)) mails := captureSeam(d) d.ProcessEvent("c1", "offsite_delivery_stuck", "info", "stuck", "{}", "hub") if len(*mails) != 0 { t.Fatalf("mails = %d, want 0 — info stays silent (severityNotifies untouched); the checker MUST emit warning", len(*mails)) } }