diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fff88f..3bb0956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,34 @@ +## v0.212.0 — the second promise (2026-08-12, R-299) — MinAgent 0.127.0 + +**R-299 — the orphan card’s OTHER sentence made the same unevaluable promise, and the spec said it was +fine.** v0.211.0 fixed the confirm block; the EXPLANATION paragraph above it +(`internal/web/templates/backups_remote.html`) still ended *„a hozzájuk tartozó helyreállítási kóddal +később **visszaállíthatók lehetnek**”* — the identical claim in the plural. + +**It survived for two independent reasons, and both are the interesting part:** + +1. `SPEC-orphan-card-copy-2026-08-10.md` §1 listed that line as *“Accurate; keep”*. The spec has been + corrected. +2. **The regression guard matched one INFLECTION.** It asserted `visszaállítható lehet` (singular); the + card carried `visszaállíthatók lehetnek` (plural), which does not contain that substring at all. **A + guard matching one inflection of a Hungarian verb guards one sentence, not the claim.** It now + matches the stem `visszaállíthat`, so any conjugation fails. Proven by planting the exact shipped + plural: the stem guard convicts and quotes it, while the old singular guard does not match it. + +**And it was the ALWAYS-VISIBLE half.** The paragraph fixed in v0.211.0 renders only after the customer +clicks „Új távoli mentés indítása…”. On first view the explanation is the only text they read — so +until now, the sentence a customer actually saw was the one still promising. + +**The two accurate halves are kept**, because declining a promise must not turn into telling the +customer less than we know: the store IS orphaned (and why), and new backups genuinely cannot be +written. New ending: *„A meglévő mentések nem sérültek. Azt viszont ez a gép nem tudja megállapítani, +hogy később megnyithatók-e — ez attól függ, megvan-e még a hozzájuk tartozó kulcs. Ha szükséged van +rájuk, írj nekünk.”* + +Also fixed in the guard itself: its failure message sliced the rendered HTML at a BYTE offset, which +cuts Hungarian mid-character and printed a replacement char — a garbled failure message reads like an +encoding bug in the product. It now slices on rune boundaries. + ## v0.211.0 — the wall a rebuilt box could not get past (2026-08-10, R-280 / R-294 / R-295) — MinAgent 0.127.0 **R-294 / R-202 — the orphan card stops promising what it cannot know.** The card told a customer, diff --git a/controller/internal/web/orphan_card_copy_test.go b/controller/internal/web/orphan_card_copy_test.go index 67d20b9..a00e5ec 100644 --- a/controller/internal/web/orphan_card_copy_test.go +++ b/controller/internal/web/orphan_card_copy_test.go @@ -3,6 +3,7 @@ package web import ( "strings" "testing" + "unicode/utf8" "gitea.dooplex.hu/admin/felhom-controller/internal/settings" ) @@ -47,10 +48,37 @@ func TestOrphanCard_DoesNotPromiseRestorability(t *testing.T) { t.Fatal("the orphan card did not render at all — this test would then pass vacuously, " + "which is the way a copy guard silently stops guarding") } - if strings.Contains(html, "visszaállítható lehet") { - t.Error("R-294: the card still promises the set-aside copies may be restorable later. The box " + - "cannot evaluate that — the discriminator (superseded identity_blob) is on the hub and no " + - "wire field carries it — and for everything set aside before 2026-08-04 it is false") + // R-299: the guard matches the STEM, not one inflection. The first version of this test asserted + // „visszaállítható lehet" (singular) and the card carried „visszaállíthatók lehetnek" (plural) one + // paragraph above it — the same claim, invisible to the guard. A guard matching one inflection of a + // Hungarian verb guards one SENTENCE, not the claim. `visszaállíthat` is the potential stem + // ("can be restored"); the plain forms the rest of the UI uses („visszaállítás", „visszaállítani") + // do not contain it, so this does not over-match. + // + // It asserts on the RENDERED bytes, which is why the explanatory {{/* */}} comment in the template + // may quote the retired wording: html/template strips it. An HTML comment would SHIP and + // would make this test unfailable — that is the R-253 trap, and it is why the comment form matters. + if idx := strings.Index(html, "visszaállíthat"); idx >= 0 { + // Slice on RUNE boundaries. Go string indexing is by byte, and cutting Hungarian text at a + // byte offset splits a multi-byte character — the failure message then shows a replacement + // char and reads like an encoding bug in the product rather than in this message. + start, end := idx-80, idx+90 + if start < 0 { + start = 0 + } + if end > len(html) { + end = len(html) + } + for start < len(html) && !utf8.RuneStart(html[start]) { + start++ + } + for end < len(html) && !utf8.RuneStart(html[end]) { + end++ + } + t.Errorf("R-294/R-299: the card still promises the set-aside copies may be restorable. The box "+ + "cannot evaluate that — the discriminator (superseded identity_blob) is on the hub and no "+ + "wire field carries it — and for everything set aside before 2026-08-04 it is false.\n"+ + " found: …%s…", html[start:end]) } } @@ -102,3 +130,32 @@ func TestOrphanCard_HealthyStoreSeesNoneOfIt(t *testing.T) { } } } + +// R-299 — the EXPLANATION paragraph keeps its two accurate halves and drops the promise. +// +// This is the always-visible half of the card; the paragraph fixed yesterday only appears after the +// customer clicks through to the confirm block. So on first view this is the ONLY text they read, +// and until now it was the one still making the promise. +func TestOrphanCard_ExplanationKeepsWhatIsTrueAndDropsThePromise(t *testing.T) { + html := renderBackupPage(t, "backups_remote", orphanCardData("orphaned")) + + // The two halves that ARE knowable from the box must survive. + for _, keep := range []string{ + "nem elérhető kulccsal", // why the store is orphaned + "nem írható a tárolóba", // the consequence right now + "nem sérültek", // the backups are intact — knowable, and reassuring for a reason + } { + if !strings.Contains(html, keep) { + t.Errorf("R-299: the explanation lost an accurate statement (%q). Declining the promise must "+ + "not turn into telling the customer less than we know", keep) + } + } + // …and the part the box cannot evaluate must be declined, with a route. + if !strings.Contains(html, "nem tudja megállapítani") { + t.Error("R-299: the explanation no longer says the machine cannot determine this — silence is " + + "not the same as declining a claim") + } + if !strings.Contains(html, "írj nekünk") { + t.Error("R-299: the explanation declines the claim but names no route") + } +} diff --git a/controller/internal/web/templates/backups_remote.html b/controller/internal/web/templates/backups_remote.html index f12e921..b868f0d 100644 --- a/controller/internal/web/templates/backups_remote.html +++ b/controller/internal/web/templates/backups_remote.html @@ -95,7 +95,13 @@ {{if eq .Offbox.RepoState "orphaned"}}

A távoli tároló másik kulccsal készült mentéseket tartalmaz

-

A távoli tárhelyen lévő mentések egy korábbi, már nem elérhető kulccsal készültek (jellemzően újratelepítés után). Emiatt új mentés jelenleg nem írható a tárolóba. A meglévő mentések nem sérültek — a hozzájuk tartozó helyreállítási kóddal később visszaállíthatók lehetnek.

+ {{/* R-299: this paragraph carried the SAME unevaluable promise as the confirm block below, in a + different conjugation („visszaállíthatók lehetnek" vs „visszaállítható lehet") — which is + also why the first regression guard, matching the singular form, did not catch it. The + discriminator is superseded identity_blob on the HUB; the box has no wire field for it. The + two accurate halves are kept: the store IS orphaned, and new backups genuinely cannot be + written. The guard now matches the STEM, so any inflection fails the test. */}} +

A távoli tárhelyen lévő mentések egy korábbi, már nem elérhető kulccsal készültek (jellemzően újratelepítés után). Emiatt új mentés jelenleg nem írható a tárolóba. A meglévő mentések nem sérültek. Azt viszont ez a gép nem tudja megállapítani, hogy később megnyithatók-e — ez attól függ, megvan-e még a hozzájuk tartozó kulcs. Ha szükséged van rájuk, írj nekünk.