R-585: the last customer-facing producers follow the household's language

backup_integrity_ok / backup_integrity_failed now take facts and push bundle
keys (Hungarian bytes unchanged - go-parity, pinned verbatim by
TestR585_IntegrityHungarianIsUnchanged). The interrupted-operation alert
(backup_failed, customer-enabled by default) used to send the operator's
ENGLISH sentence to every household; NotifyInterruptedOperation composes it
per language, the English byte-identical to the operator's log line. The
now-callerless NotifyBackupFailed is removed. local_api_endpoint_drift is
operator-only (no customer toggle) and already English by design - not
changed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-06 01:20:03 +02:00
parent 84d6ef706d
commit ff1758a21c
10 changed files with 289 additions and 45 deletions
+28 -9
View File
@@ -5,6 +5,8 @@ import (
"go/parser"
"go/token"
"testing"
"gitea.dooplex.hu/admin/felhom-controller/internal/i18n"
)
// R-359 — the scheduled job must be PROVEN WIRED.
@@ -87,16 +89,33 @@ func TestR359_DebugCallbackIsWired(t *testing.T) {
func TestR359_OutcomeMessagesCarryNoMachineDetail(t *testing.T) {
// The customer gets a sentence; restic's words go to the log. R-379: 615 bytes of raw database
// text reached a customer once.
for _, bad := range []string{"sftp:", "restic", "exit status", "@", "/srv/"} {
if contains(integrityFailedMsg, bad) {
t.Errorf("the failure sentence carries machine detail %q: %q", bad, integrityFailedMsg)
}
// text reached a customer once. R-585: the sentence is a bundle key now, so BOTH languages are
// held to it — an English household must be told what not to do just as plainly.
b, err := i18n.Shared()
if err != nil {
t.Fatal(err)
}
// It must still tell them what to do — and what NOT to do.
for _, want := range []string{"Ne törölj semmit", "vedd fel velünk a kapcsolatot"} {
if !contains(integrityFailedMsg, want) {
t.Errorf("the failure sentence is a dead end; missing %q", want)
for _, tc := range []struct {
lang string
wants []string
}{
{"hu", []string{"Ne törölj semmit", "vedd fel velünk a kapcsolatot"}},
{"en", []string{"Do not delete anything", "contact us"}},
} {
msg, fellBack, ok := b.Text(tc.lang, "event.backup_integrity_failed")
if !ok || fellBack {
t.Fatalf("%s: event.backup_integrity_failed is missing (ok=%v fellBack=%v)", tc.lang, ok, fellBack)
}
for _, bad := range []string{"sftp:", "restic", "exit status", "@", "/srv/"} {
if contains(msg, bad) {
t.Errorf("%s: the failure sentence carries machine detail %q: %q", tc.lang, bad, msg)
}
}
// It must still tell them what to do — and what NOT to do.
for _, want := range tc.wants {
if !contains(msg, want) {
t.Errorf("%s: the failure sentence is a dead end; missing %q", tc.lang, want)
}
}
}
}