v0.297.0: burn-down round 2 — 24 small rows (R-591 R-568 R-567 R-363 R-547 R-10 R-552 R-251 R-104 R-619 R-362 R-675 R-256 R-257 R-240 R-365 R-425 R-565 R-564 R-603 R-454 R-208 R-457-swept) + the banner countdown and deepCopyStack twins; MinAgent 0.131.0
gates / gates (push) Failing after 50s

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:
2026-10-05 20:12:56 +02:00
parent 114ff2761a
commit 1453cfc69b
68 changed files with 3953 additions and 116 deletions
@@ -100,6 +100,26 @@ func i18nCases() []i18nCase {
d["ShareFlash"] = "A megosztás bekapcsolva."
return d
}},
// R-365 follow-up: the countdown's due moment has passed, the daily sweep has not run yet.
{"launcher_abandon_overdue", "launcher", func() map[string]interface{} {
d := i18nLayoutData("launcher", "Indítópult")
d["RecoveryBanner"] = true
d["RecoveryBannerBack"] = "/launcher"
d["RecoveryAbandonDays"] = 0
d["RecoveryAbandonOverdue"] = true
d["RecoveryAbandonDate"] = "2026-09-29"
return d
}},
{"launcher_abandon_overdue_offered", "launcher", func() map[string]interface{} {
d := i18nLayoutData("launcher", "Indítópult")
d["RecoveryBanner"] = true
d["RecoveryBannerBack"] = "/launcher"
d["RecoveryAbandonDays"] = 0
d["RecoveryAbandonOverdue"] = true
d["RecoveryAbandonDate"] = "2026-09-29"
d["RecoveryAbandonRetrievalOffered"] = true
return d
}},
{"launcher_empty", "launcher", func() map[string]interface{} {
d := i18nLayoutData("launcher", "Indítópult")
d["RecoveryBanner"] = true
@@ -564,6 +584,38 @@ func huLetter(s string) bool {
return strings.ContainsAny(s, "áéíóöőúüűÁÉÍÓÖŐÚÜŰ")
}
// asciiHuRe (R-565) is the extractor's ASCII-only Hungarian word list (scripts/i18n_extract.py
// ASCII_HU), plus the words releases B and C found by eye after every test was green (mp, db, FIGYELEM,
// jelenlegi, majd a(z), Konfig, Megtartva, …). An unaccented Hungarian word is invisible to huLetter,
// and those six fragments reached English pages with no test failing. Case-insensitive, whole words.
// Words that are also ordinary English or markup („Nem", „pl", „nap", „ora", „Csak" never clash, but
// „Fut"/„Perc" would match nothing English either) are kept; a word that DOES collide with English
// copy or markup must be removed here with a reason, never by weakening the mask.
var asciiHuRe = regexp.MustCompile(`(?i)\b(Fut|Nincs|Igen|Nem|Hiba|Mentve|Rendben|Adatok|Napi|Heti|Havi|Mindig|Soha|Tegnap|` +
`Perc|Letiltva|Bekapcsolva|Kikapcsolva|Folyamatban|Sikertelen|Sikeres|Tartalom|` +
`Kapcsolat|Vissza|Megosztva|Kezdeti|Rendszer|Csatlakozva|Kulcs|Megnyit|Elrejt|` +
`Ismeretlen|Szabad|Foglalt|Kijelentkezes|Napok|nap|perc|ora|` +
`Megszakadt|Elavult|Csak|kompatibilis|Rendszermonitor|Most nem|` +
`Folyamat|Titkos|Processzor|Hamarosan|aldomain|adatai|Figyelem|pelda|` +
`Konfig|Megtartva|helyi|pl|Befejezve|automatikus|jelenleg|kedd|szerda|szombat|szint|` +
// release C (R-556): found by eye in JS strings, no test failed on any of them
`jelenlegi|mp|\d+ db)\b|\bmajd a\(z\)`)
// „db" (darab) only after a number: bare, it is markup (class="db-table", data-has-db) and the English
// abbreviation „DB". The count word the review found was always „<n> db".
var htmlTagRe = regexp.MustCompile(`<[^>]*>`)
var urlLikeRe = regexp.MustCompile(`\b[\w-]+(?:\.[\w-]+)+(?:/[\w./-]*)?`)
// asciiHuWord returns the first ASCII-only Hungarian word in s's COPY, or "". Tags (attribute values
// such as value="helyi" are code, not copy) and host/path tokens (felhom.eu/kapcsolat) are removed
// first; JavaScript string literals stay in, because inline JS copy is page copy.
func asciiHuWord(s string) string {
s = htmlTagRe.ReplaceAllString(s, " ")
s = urlLikeRe.ReplaceAllString(s, " ")
return asciiHuRe.FindString(s)
}
// fixtureStrings collects every string the fixture DATA carries (catalog copy, Go-side messages the
// handler would build). Those are not template copy: they are slices 2 and 5 of the plan, and the
// English page check subtracts them rather than pretending the template could translate them.
@@ -609,6 +661,16 @@ func TestI18nEnglishPages(t *testing.T) {
if huLetter("Backup completed at 03:00, next run tomorrow.") {
t.Fatal("control: the detector flags plain English")
}
// R-565 controls for the ASCII word detector: a planted „mp" in an English value is caught, and a
// plain English sentence is not.
for _, planted := range []string{"label += ' · ' + p.elapsed_sec + ' mp';", "FIGYELEM: the drive", "then majd a(z) app", "3 db"} {
if asciiHuWord(planted) == "" {
t.Fatalf("control: the ASCII detector does not flag ASCII-only Hungarian in %q", planted)
}
}
if w := asciiHuWord(`Backup completed at 03:00, next run tomorrow; 3 items, 12 seconds left. <table class="db-table"> Config + DB + Data, see felhom.eu/kapcsolat`); w != "" {
t.Fatalf("control: the ASCII detector flags plain English (%q)", w)
}
for _, c := range i18nCases() {
hu := renderI18nCase(t, s, "hu", c)
@@ -651,10 +713,20 @@ func TestI18nEnglishPages(t *testing.T) {
}
stripped = strings.ReplaceAll(stripped, k, "")
}
// R-565: a ONE-word data value is not masked above (it could hide template copy), but the ASCII
// detector would read it as copy. Mask it only where it is an element's WHOLE text — exactly
// how data renders (catalog default credentials „nincs"), never inside a sentence.
for _, k := range keys {
if len(strings.Fields(k)) == 1 {
stripped = strings.ReplaceAll(stripped, ">"+k+"<", "><")
}
}
// Script/style bodies are included on purpose: inline JS copy is page copy.
for i, line := range strings.Split(stripped, "\n") {
if huLetter(line) {
t.Errorf("%s: Hungarian template copy on the English page, line %d: %q", c.name, i+1, strings.TrimSpace(line))
} else if w := asciiHuWord(line); w != "" {
t.Errorf("%s: ASCII-only Hungarian word %q on the English page (R-565), line %d: %q", c.name, w, i+1, strings.TrimSpace(line))
}
}
}