v0.259.0 — the claim page and the backup warnings answer in the reader's language (R-596, R-598)
gates / gates (push) Successful in 28s

The 2026-09-20 English drill ended one screen short: the claim page was English
and its answers were Hungarian, so a household who mistyped the code from their
e-mail could not tell a typo from a dead code. Fourteen call sites carrying nine
messages now go through s.msg; the backup page's two protection warnings — which
are promises about whether the customer's files are safe — follow the same route.

Hungarian is byte-identical, proved structurally by the go-parity gate against the
frozen base capture and red-proofed on a single added full stop.

data["Title"] was DEAD (claim.html is standalone; .Title is layout.html's) and is
deleted rather than translated — a translated dead field is a permanent false
signal about where the page's title comes from.

Six existing copy-contract tests were kept, not weakened: each now resolves its key
through the real bundle, so it still convicts on a reworded Hungarian sentence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-21 07:45:56 +02:00
parent f6909492cc
commit 0fe04bb6d5
15 changed files with 736 additions and 143 deletions
@@ -6,6 +6,7 @@ import (
"testing"
"gitea.dooplex.hu/admin/felhom-controller/internal/agentapi"
"gitea.dooplex.hu/admin/felhom-controller/internal/i18n"
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
)
@@ -48,6 +49,28 @@ func absentHarness(t *testing.T, primary string, disks []agentapi.DiskInfo, regi
return s
}
// huText renders a bundle KEY into the Hungarian a household actually reads.
//
// v0.259.0 (R-598) turned the three backup-protection constants into bundle keys, so every
// assertion below would otherwise have quietly become an assertion about key SPELLING — the exact
// hollowing this repo has paid for before. Resolving through the real embedded bundle keeps them
// assertions about the WORDS, and fails loudly if a key is ever dropped from hu.json.
func huText(t *testing.T, key string) string {
t.Helper()
if key == "" {
return ""
}
b, err := i18n.Shared()
if err != nil {
t.Fatalf("i18n bundle: %v", err)
}
got := b.Msg("hu", key)
if got == key {
t.Fatalf("the bundle does not know %q — it would render the KEY onto the page", key)
}
return got
}
// theVanishedDrive is the E-2d shape: registered, still carrying its configured MountPath, user-data,
// but no longer claiming the backup target because its device is gone.
var theVanishedDrive = agentapi.DiskInfo{
@@ -73,7 +96,7 @@ func TestConfiguredButAbsentTargetDoesNotClaimTheSystemDisk(t *testing.T) {
t.Fatalf("TargetAbsent is false for target %q with no disk claiming it — the configured-but-gone "+
"state fell back into never-configured, which is the R-114 bug", st.TargetID)
}
msg := degradedMessageFor(st)
msg := huText(t, degradedMessageFor(st))
if strings.Contains(msg, "ugyanazon a lemezen") {
t.Errorf("the customer is told the backup is on the SYSTEM DISK, which is false — the target is "+
"%q, a drive that has vanished. Got: %s", st.TargetID, msg)
@@ -130,7 +153,7 @@ func TestNeverConfiguredStillSaysSystemDiskAndStillOffers(t *testing.T) {
if !st.Degraded {
t.Fatal("a backup on the system disk must still read degraded")
}
if msg := degradedMessageFor(st); !strings.Contains(msg, "ugyanazon a lemezen") {
if msg := huText(t, degradedMessageFor(st)); !strings.Contains(msg, "ugyanazon a lemezen") {
t.Errorf("the never-configured copy changed; got: %s", msg)
}
if st.OfferPath == "" {
@@ -164,7 +187,7 @@ func TestHealthyTargetIsNeitherDegradedNorAbsent(t *testing.T) {
if st.Degraded || st.TargetAbsent {
t.Fatalf("a healthy target reported degraded=%v absent=%v", st.Degraded, st.TargetAbsent)
}
if msg := degradedMessageFor(st); msg != "" {
if msg := huText(t, degradedMessageFor(st)); msg != "" {
t.Errorf("healthy produced copy %q — a working box must look normal", msg)
}
}
@@ -176,11 +199,12 @@ func TestHealthyTargetIsNeitherDegradedNorAbsent(t *testing.T) {
func TestAbsentCopyMatchesTheHubEmailWordForWord(t *testing.T) {
const hubCopy = "A rendszermentés meghajtója nem érhető el — amíg vissza nem " +
"csatlakoztatod, a teljes rendszermentés nem készül el."
if backupTargetAbsentText != hubCopy {
banner := huText(t, backupTargetAbsentKey)
if banner != hubCopy {
t.Errorf("the banner and the email now tell the customer different stories about one drive.\n"+
" banner: %s\n email : %s", backupTargetAbsentText, hubCopy)
" banner: %s\n email : %s", banner, hubCopy)
}
msg := degradedMessageFor(BackupTargetState{Known: true, Degraded: true, TargetAbsent: true})
msg := huText(t, degradedMessageFor(BackupTargetState{Known: true, Degraded: true, TargetAbsent: true}))
for _, want := range []struct{ frag, why string }{
{"nem érhető el", "the FACT — the drive cannot be reached"},
{"nem készül el", "the CONSEQUENCE — the full system backup does not happen"},