135a8b02aa
The customer mail of health_degraded / health_critical / health_recovered no longer appends the raw details JSON (frozen wire text, English or Hungarian whatever the household's language). It says where to read the details: the dashboard. The operator mail keeps the note; every other event keeps its note. Red tests: r79_health_mail_test.go (2 failed on the old templates.go). Goldens regenerated for the six health mails. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
67 lines
3.0 KiB
Go
67 lines
3.0 KiB
Go
package notify
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// R-79 (D3, operator ruling 2026-10-08, `09` §3 decision 187): the HOUSEHOLD's system-health mail
|
|
// no longer carries the raw details JSON — a curly-bracket note with English lines in it that the
|
|
// household could not read. It says in plain words that something needs attention and points to the
|
|
// dashboard, where each issue is shown in the household's language. The OPERATOR's mail keeps the
|
|
// note, and every other event type keeps its note too.
|
|
|
|
const r79HealthDetails = `{"previous_status":"ok","current_status":"fail","issues":["Protected container not running: cloudflared"]}`
|
|
|
|
func TestR79_CustomerHealthMailHasNoRawNote(t *testing.T) {
|
|
for _, et := range []string{"health_critical", "health_degraded", "health_recovered"} {
|
|
for _, tc := range []struct{ lang, pointer string }{
|
|
{"hu", "vezerl"}, // ASCII fragment of „vezérlőpult" (accented greps lie)
|
|
{"en", "dashboard"},
|
|
} {
|
|
_, body := FormatCustomerEmail(tc.lang, "c1", et, "error", "msg", "", r79HealthDetails)
|
|
if strings.Contains(body, "{") || strings.Contains(body, "issues") ||
|
|
strings.Contains(body, "Protected container") {
|
|
t.Errorf("%s/%s: customer mail still carries the raw note:\n%s", et, tc.lang, body)
|
|
}
|
|
if !strings.Contains(asciiFold(body), tc.pointer) {
|
|
t.Errorf("%s/%s: customer mail lacks the dashboard pointer %q:\n%s", et, tc.lang, tc.pointer, body)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Negative control: a health event with no details still gets the pointer (it is the event that
|
|
// carries it, not the note), and the pointer never appears on a non-health event.
|
|
func TestR79_PointerOnlyOnHealthEvents(t *testing.T) {
|
|
_, body := FormatCustomerEmail("en", "c1", "health_critical", "error", "msg", "", "")
|
|
if !strings.Contains(body, "dashboard") {
|
|
t.Errorf("health mail without details lacks the pointer:\n%s", body)
|
|
}
|
|
_, other := FormatCustomerEmail("en", "c1", "backup_failed", "error", "msg", "", `{"stack_name":"x"}`)
|
|
if strings.Contains(other, "on your dashboard") {
|
|
t.Errorf("a non-health event got the health pointer:\n%s", other)
|
|
}
|
|
}
|
|
|
|
func TestR79_OperatorHealthMailKeepsNote(t *testing.T) {
|
|
_, body := FormatOperatorEmail("c1", "health_critical", "error", "msg", r79HealthDetails)
|
|
if !strings.Contains(body, "Protected container not running: cloudflared") {
|
|
t.Errorf("operator mail lost the details:\n%s", body)
|
|
}
|
|
}
|
|
|
|
func TestR79_NonHealthCustomerMailKeepsNote(t *testing.T) {
|
|
_, body := FormatCustomerEmail("hu", "c1", "backup_failed", "error", "msg", "", `{"reason":"disk full"}`)
|
|
if !strings.Contains(body, `{"reason":"disk full"}`) {
|
|
t.Errorf("non-health customer mail lost its note:\n%s", body)
|
|
}
|
|
}
|
|
|
|
// asciiFold drops the Hungarian accents so a search can use an ASCII fragment.
|
|
func asciiFold(s string) string {
|
|
r := strings.NewReplacer("á", "a", "é", "e", "í", "i", "ó", "o", "ö", "o", "ő", "o", "ú", "u", "ü", "u", "ű", "u",
|
|
"Á", "A", "É", "E", "Í", "I", "Ó", "O", "Ö", "O", "Ő", "O", "Ú", "U", "Ü", "U", "Ű", "U")
|
|
return r.Replace(s)
|
|
}
|