R-299: the orphan card's second promise, and a guard that matched one inflection
gates / gates (push) Successful in 14s
gates / gates (push) Successful in 14s
The explanation paragraph - the always-visible half of the card - still ended 'a hozzajuk tartozo helyreallitasi koddal kesobb visszaallithatok lehetnek', the same unevaluable claim v0.211.0 removed from the confirm block below it. It survived because the spec called that line accurate, and because the regression guard asserted the SINGULAR form while the card carried the plural, which does not contain that substring. The guard now matches the stem, so any conjugation fails it. The two accurate halves are kept. Also: the guard's failure message sliced rendered HTML at a byte offset and cut Hungarian mid-character; it now slices on rune boundaries.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,13 @@
|
||||
{{if eq .Offbox.RepoState "orphaned"}}
|
||||
<div class="card" style="border-left:3px solid var(--crit,#e5484d);margin:.75rem 0;padding:.75rem 1rem" id="offbox-orphan-card">
|
||||
<p style="margin:0 0 .35rem;font-weight:600">A távoli tároló másik kulccsal készült mentéseket tartalmaz</p>
|
||||
<p class="form-hint" style="margin:0 0 .5rem">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.</p>
|
||||
{{/* 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. */}}
|
||||
<p class="form-hint" style="margin:0 0 .5rem">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.</p>
|
||||
<button type="button" class="btn btn-sm btn-outline" id="orphan-reveal" onclick="var c=document.getElementById('orphan-confirm');c.style.display='block';this.style.display='none'">Új távoli mentés indítása…</button>
|
||||
<div id="orphan-confirm" style="display:none;margin-top:.6rem">
|
||||
{{/* R-294 / R-202: this paragraph promised the set-aside copies "may be restorable later
|
||||
|
||||
Reference in New Issue
Block a user