R-1348: the mail of an interrupted put-back names a restore, not an off-site run (seen on the live proof); changelog: R-1347, R-1348 proven live on 9202. Commit only.
gates / gates (push) Successful in 32s

This commit is contained in:
admin committed 2026-11-03 01:12:19 +01:00
1 parent c4b6844d34
commit 37644458c7
4 files changed
+40 -7

No files matched your search

+6 -1
View File
@@ -16,7 +16,12 @@ skipped it until the controller restarted. New seam `backup.SetUpdateHeldForgett
**R-1348 — a failed put-back at start-up mails the operator.** `holdPutBackFailed` writes the D20 hold at `Recover`, before any
notifier exists, so only the hold reporter's info and the hub's later reminder said anything. `AppStopGuard.SetHeldNotify`
hands over what `Recover` held, once, and mails a later failure (a drive that returned) at once: the R-1340 sentence for
`MixedCauseInterruptedPutBack`, from the hold record. Tests `TestR1348_*`.
`MixedCauseInterruptedPutBack`, from the hold record. The mail's run name says „restore" for it, not „offsite-reconstitute"
(`heldRunKind`, seen on the live proof). Tests `TestR1348_*`. **Live proof 2026-11-03, scratch 9202, test image of c4b6844** (felhom.eu
`audits/security-2026-11-02/part3/`): a restore cut at „the restore copy is recorded", the volume held by a created-only
container, the controller started: hold `restore_mixed` / `interrupted_put_back`, the event `backup_run_failures` with the sentence in the sink.
**R-1347's live proof, same image:** an update with its undo copy cut off → hold `update_failed`; the household's restore → „the update hold is CLEARED", „its
update-held flag is forgotten"; six `kill -9` → the crash-loop watcher stops the app (`unhealthy_stop`), so it watches again.
**R-1339 — no false „drive … not mounted".** A per-app folder under a mounted drive is never a mountpoint itself; nine false lines
at every start on 9202. The folder still gets no bind and no skeleton of its own (the row's „not skipped" would write a
+10
View File
@@ -78,6 +78,16 @@ func heldStoppedOperatorText(h settings.RestoreHold) (msg, leg, reason string) {
}
}
// heldRunKind names the run in the mail's subject. A hold that does not say which restore wrote it is an off-site one, the
// pre-R-1340 rule, EXCEPT an interrupted put-back: its record names no kind, and its restore may be either, so „restore" (R-1348,
// seen live 2026-11-03: a local restore's mail read „offsite-reconstitute"). Pinned by TestR1348_HeldRunKind.
func heldRunKind(h settings.RestoreHold) string {
if h.RestoreKind == settings.RestoreKindLocal || h.MixedCause == settings.MixedCauseInterruptedPutBack {
return "restore"
}
return "offsite-reconstitute"
}
func mixedHoldText(h settings.RestoreHold, kind, tail string) (msg, leg, reason string) {
stack := h.Stack
leg = "restore-hold-mixed"
+1 -5
View File
@@ -1560,11 +1560,7 @@ func main() {
holdNotify := func(stack string, replayErr, rollbackErr error) {
h := heldHoldFromNotify(sett.GetRestoreHold, stack, replayErr, rollbackErr)
msg, leg, reason := heldStoppedOperatorText(h)
runKind := "offsite-reconstitute"
if h.RestoreKind == settings.RestoreKindLocal {
runKind = "restore"
}
d := notify.BackupRunFailuresDetails{RunKind: runKind, Failed: 1, Attempted: 1}
d := notify.BackupRunFailuresDetails{RunKind: heldRunKind(h), Failed: 1, Attempted: 1}
d.Apps = append(d.Apps, notify.RunFailureDetail{App: stack, Leg: leg, Reason: reason})
notifier.NotifyBackupRunFailures(msg, d)
}
@@ -1,6 +1,10 @@
package main
import "testing"
import (
"testing"
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
)
// R-1347 and R-1348: each seam is CALLED from main.go (an AST walk) — a seam built and never wired is the project's
// oldest shape.
@@ -17,3 +21,21 @@ func TestR1348_HeldNotifyIsWiredAtStartup(t *testing.T) {
t.Fatal("main.go never calls SetHeldNotify — a failed put-back at start-up would mail nobody")
}
}
// The mail's run name for an interrupted put-back. RED (2026-11-03, live on 9202): the sink showed run_kind offsite-reconstitute for a
// local restore.
func TestR1348_HeldRunKind(t *testing.T) {
for _, c := range []struct {
h settings.RestoreHold
want string
}{
{settings.RestoreHold{Reason: settings.HoldReasonRestoreMixed, MixedCause: settings.MixedCauseInterruptedPutBack}, "restore"},
{settings.RestoreHold{RestoreKind: settings.RestoreKindLocal}, "restore"},
{settings.RestoreHold{RestoreKind: settings.RestoreKindOffsite}, "offsite-reconstitute"},
{settings.RestoreHold{Reason: settings.HoldReasonRestoreMixed}, "offsite-reconstitute"},
} {
if got := heldRunKind(c.h); got != c.want {
t.Errorf("%+v: run kind %q, want %q", c.h, got, c.want)
}
}
}