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:
@@ -403,9 +403,55 @@ func (n *Notifier) NotifyHealthChange(status string, issues, warnings []string)
|
||||
}
|
||||
}
|
||||
|
||||
// NotifyBackupFailed sends a backup failure event.
|
||||
func (n *Notifier) NotifyBackupFailed(message, errMsg string) {
|
||||
n.PushEvent("backup_failed", "error", message, BackupDetails{Error: errMsg})
|
||||
// InterruptedOperation is the FACTS of an app-stopping operation a controller restart interrupted
|
||||
// (backup.AppStopRecovery.Facts): which kind it was, and how many apps were restarted, could not be
|
||||
// restarted, or are held by an absent drive. Counts only — app names travel in the detail.
|
||||
type InterruptedOperation struct {
|
||||
// ReasonKey is the bundle key naming the operation ("appstop.reason.*"); Reason is the raw reason,
|
||||
// used only when ReasonKey is empty (a reason this build has no sentence for).
|
||||
ReasonKey string
|
||||
Reason string
|
||||
Restarted int
|
||||
Failed int
|
||||
Refused int
|
||||
}
|
||||
|
||||
// NotifyInterruptedOperation reports, as a `backup_failed` event, that an app-stopping operation was cut
|
||||
// short by a controller restart (R-585). It used to send the OPERATOR's English sentence to every
|
||||
// household — `backup_failed` is customer-enabled by default — so a Hungarian household's mail carried
|
||||
// one English line. The sentence is now composed per language: the operation's name is rendered in the
|
||||
// SAME language as the sentence around it, which is why this does not go through pushEventMsg (whose
|
||||
// arguments are the same for both languages). detail is the machine tail (names only, never env values).
|
||||
func (n *Notifier) NotifyInterruptedOperation(op InterruptedOperation, detail string) {
|
||||
b, err := i18n.Shared()
|
||||
if err != nil {
|
||||
n.logger.Printf("[ERROR] NotifyInterruptedOperation: bundle unavailable: %v", err)
|
||||
n.pushEventBoth("backup_failed", "error", "event.appstop.restarted", "", BackupDetails{Error: detail})
|
||||
return
|
||||
}
|
||||
render := func(lang string) string {
|
||||
reason := op.Reason
|
||||
if op.ReasonKey != "" {
|
||||
reason = b.Msg(lang, op.ReasonKey)
|
||||
}
|
||||
switch {
|
||||
case op.Failed > 0 && op.Refused > 0:
|
||||
return b.Msgf(lang, "event.appstop.failed_held", reason, op.Failed, op.Restarted+op.Failed, op.Refused)
|
||||
case op.Failed > 0:
|
||||
return b.Msgf(lang, "event.appstop.failed", reason, op.Failed, op.Restarted+op.Failed)
|
||||
case op.Restarted == 0 && op.Refused > 0:
|
||||
return b.Msgf(lang, "event.appstop.held", reason, op.Refused)
|
||||
case op.Refused > 0:
|
||||
return b.Msgf(lang, "event.appstop.restarted_held", reason, op.Restarted, op.Refused)
|
||||
default:
|
||||
return b.Msgf(lang, "event.appstop.restarted", reason, op.Restarted)
|
||||
}
|
||||
}
|
||||
household := ""
|
||||
if lang := n.boxLang(); lang != i18n.Default {
|
||||
household = render(lang)
|
||||
}
|
||||
n.pushEventBoth("backup_failed", "error", render(i18n.Default), household, BackupDetails{Error: detail})
|
||||
}
|
||||
|
||||
// RecoveryUnitFailureDetails is the machine-readable tail of a Tier-1 capture failure. App NAMES and
|
||||
@@ -513,8 +559,13 @@ func (n *Notifier) NotifyDBDumpCompleted(details DBDumpDetails) {
|
||||
}
|
||||
|
||||
// NotifyIntegrityFailed sends a backup integrity check failure event.
|
||||
func (n *Notifier) NotifyIntegrityFailed(message, errMsg string) {
|
||||
n.PushEvent("backup_integrity_failed", "error", message, &BackupDetails{Error: errMsg})
|
||||
//
|
||||
// R-585: the sentence is a bundle key, so it follows the household's language. It names what to do and
|
||||
// what NOT to do („Ne törölj semmit" is load-bearing — a household that believes its backups are broken
|
||||
// may "start fresh" and destroy the one copy that might still be partly recoverable); both languages are
|
||||
// pinned by TestR359_OutcomeMessagesCarryNoMachineDetail. errMsg is the machine cause, never the sentence.
|
||||
func (n *Notifier) NotifyIntegrityFailed(errMsg string) {
|
||||
n.pushEventMsg("backup_integrity_failed", "error", "event.backup_integrity_failed", &BackupDetails{Error: errMsg})
|
||||
}
|
||||
|
||||
// NotifyOffsiteProofEmpty (R-87) reports that the nightly off-site proof found a backup that is
|
||||
@@ -535,8 +586,16 @@ func (n *Notifier) NotifyOffsiteProofEmpty(message, detail string) {
|
||||
}
|
||||
|
||||
// NotifyIntegrityOK sends a backup integrity check success event.
|
||||
func (n *Notifier) NotifyIntegrityOK(message string) {
|
||||
n.PushEvent("backup_integrity_ok", "info", message, nil)
|
||||
//
|
||||
// R-585: it takes the FACTS — how long the check ran, and how much of the stored data it re-read
|
||||
// (empty for a structure-only pass) — so the sentence follows the household's language. The depth is a
|
||||
// fact the sentence has to carry: "checked" means two different things depending on it.
|
||||
func (n *Notifier) NotifyIntegrityOK(duration, readDataSubset string) {
|
||||
if readDataSubset != "" {
|
||||
n.pushEventMsg("backup_integrity_ok", "info", "event.backup_integrity_ok_subset", nil, duration, readDataSubset)
|
||||
return
|
||||
}
|
||||
n.pushEventMsg("backup_integrity_ok", "info", "event.backup_integrity_ok", nil, duration)
|
||||
}
|
||||
|
||||
// NotifyControllerUpdated sends a controller update event.
|
||||
|
||||
Reference in New Issue
Block a user