95c10954ae
gates / gates (push) Successful in 23s
10-localisation.md §10.3: the saved notes follow the box language at write time, with the one-night consequence stated rather than hidden; the globe, and the table of WHO reads which page and where its globe posts — getting that wrong makes the button do nothing, which it did on /recovery until the live probe found it. Decision 6 superseded a second time; decision 8 (a claim carries the visitor's language) recorded. Decision 5 of §11's anonymous-surface line: changing what a VISITOR reads is within what an anonymous request may do; changing anything the household owns is not, and POST /lang can do only the first. R-578 — the deadlock, and why it is a row rather than a fixed bug: UpdateOffboxStatus holds the settings write lock while running its callback, boxLang() wants the read lock, sync.RWMutex is not reentrant. On a real box an off-site run would have hung FOREVER holding that lock. The symptom was a test suite going from 8 minutes to a 25-minute timeout. Fixed and guarded, but the guard covers one package and three helper names; the class needs a gate. R-577 — a guest share visitor still has no way to pick a language, and the household's setting is the wrong default for a stranger. Deliberately left, pinned by a test, and the operator's to decide because it is a promise the share feature makes. .claude/rules/live-probes.md, unconditional: never send a deploy request for an app that is not installed, not even expecting a refusal — the endpoint accepts first and validates later. Two sessions made that mistake in two days, the second WITH a prompt line forbidding it. A prompt is read once; a rule file is loaded every session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
95 lines
6.6 KiB
Plaintext
95 lines
6.6 KiB
Plaintext
RED-PROOFS — localisation slice 2 release A (v0.252.0), 2026-09-18
|
|
Each line: what was broken, what convicted, restored green after.
|
|
|
|
1. scripts/i18n_go_parity.py — one byte added to a hu.json value
|
|
planted: hu.json "redproof.test" = "Érvénytelen kérés!" (base literal has no "!")
|
|
CONVICTS: CHANGED redproof.test / hu.json 'Érvénytelen kérés!' / base 'Érvénytelen kérés'
|
|
2. scripts/i18n_go_parity.py — a key citing text nobody wrote
|
|
planted: from = "Ez a mondat sosem létezett"
|
|
CONVICTS: INVENTED redproof.test cites text that is in no base-commit literal
|
|
3. scripts/i18n_go_parity.py — a joined key whose fragments were reworded
|
|
planted: from = ["Az alkalmazás (", ") törölve lett."] (neither fragment is a base literal)
|
|
CONVICTS: INVENTED ... 'Az alkalmazás ('
|
|
4. scripts/i18n_go_parity.py — its own scanner's blind spot, found by the gate IN USE
|
|
the first capture filtered by an ASCII-Hungarian WORD LIST and missed 7 real literals
|
|
("Naponta", "5 percenkent", "Eletjel (Heartbeat)", "Adatbazis mentes", "Biztonsagi mentes",
|
|
"Mentes integritas", "Rendszer allapot"). The gate refused the keys citing them. Fixed by
|
|
indexing EVERY literal; the word list is gone. NOT a planted decoy — a live catch.
|
|
5. internal/notify wire golden — one byte changed in an event message
|
|
planted: "Alkalmazás telepítve: %s" -> "Alkalmazás telepitve: %s"
|
|
CONVICTS: TestEventMessageWireTextIsFrozen/one_parameter, got vs want printed
|
|
6. internal/monitor wire golden — a wire warning translated
|
|
planted: warnFmtStorageUnavailable -> "Storage not reachable: %s"
|
|
CONVICTS: TestStorageWarningWireTextIsFrozen/unavailable AND TestStorageWarningFormatsAreFrozen
|
|
7. internal/web — a Server with no bundle field renders raw keys
|
|
planted: s.bundle() returns s.i18n unchanged (no i18n.Shared fallback)
|
|
CONVICTS: TestFlashOnAServerWithNoBundleField — showed "flash.share.enabled"
|
|
|
|
RELEASE B (v0.253.0), 2026-09-18 — errors carry a key
|
|
|
|
8. util.msgError.Error() returns ENGLISH instead of Hungarian
|
|
CONVICTS: TestMsgErrorKeepsKindAndHuText — "%v printed 'That setting is not valid: …'"
|
|
9. Unwrap() returns the kind ALONE (the old KindErrorf behaviour)
|
|
CONVICTS: TestMsgErrorUnwrapsTheCauseToo — "the wrapped CAUSE is unreachable"
|
|
10. ErrText rewrites a FOREIGN error (restic/docker/stdlib) instead of passing it through
|
|
CONVICTS: TestErrTextFallsBackVerbatim, both languages
|
|
11. an inner error argument is pre-rendered in Hungarian instead of recursively
|
|
CONVICTS: TestErrTextRendersAWrappedMessageErrorToo
|
|
12. err.Error() put back at a converted display sink (storage_handlers.go:822)
|
|
CONVICTS: TestNoErrErrorInPageOutput, naming the file, the line and the call
|
|
13. the English plural collapsed to the singular (alert.deadapp.group.other)
|
|
CONVICTS: TestPluralEnglish — "4 installed app is not running"
|
|
14. Hungarian GIVEN a plural form it must not have
|
|
CONVICTS: TestPluralEnglish — "the Hungarian sentence moved"
|
|
|
|
TWO LIVE CATCHES IN RELEASE B — neither planted:
|
|
A. The bulk converter SILENTLY DROPPED the continuation of a multi-line concatenation
|
|
(`fmt.Errorf("a: "+ "b: %s", x)` kept only "a: "), damaging 7 producers. Found by
|
|
TestR356_ScenarioC and TestR379_ScenarioA, which assert the SENTENCE a customer reads.
|
|
The parity gate did NOT catch it: every surviving fragment was byte-equal to a base literal,
|
|
so the gate's question ("is this text real?") was answered yes while the CALL had lost text.
|
|
All 7 rebuilt as joined keys; the six wrong keys pruned from both bundles.
|
|
B. My own counting script was CASE-SENSITIVE, so it reported "0 error literals left" while five
|
|
remained ("occ parancs sikertelen", "hub hiba", "OnlyOffice aldomain nem ismert" x2). The
|
|
R-565 shape, in the instrument. Re-measured with re.I; the five are converted.
|
|
|
|
RELEASE C (v0.254.0), 2026-09-18 — saved notes, and a globe for the language switch
|
|
|
|
15. langFor drops the `!s.hasSession(r)` guard (a signed-in household inherits a visitor's cookie)
|
|
CONVICTS: TestLangForPrecedence/SESSION_→_the_household's_setting,_cookie_NOT_read
|
|
— langFor = "en", want "hu"
|
|
16. safeBackPath allows a protocol-relative URL (an open redirect off the box)
|
|
CONVICTS: TestLangCookieHandler/back_may_only_be_a_same-origin_path
|
|
— back="//evil.example/x" → Location "//evil.example/x", want "/"
|
|
17. the R-570 producer is translated (the one saved sentence release C may not touch)
|
|
CONVICTS: TestR570SentenceStaysHungarian, BOTH arms — the literal is gone AND a bundle key
|
|
appeared, each named separately
|
|
18. one byte changed inside the FOOTER parity-exception block (lang-globe-menu → -menu2)
|
|
CONVICTS: TestI18nParity on all 101 re-captured fixtures
|
|
19. one byte changed inside the SHELL parity-exception block (shell-lang → shell-lang2)
|
|
CONVICTS: TestI18nParity naming login at line 11
|
|
|
|
TWO LIVE CATCHES IN RELEASE C — neither planted:
|
|
C. The parity HARNESS rendered the three visitor shells through addLanguageData, the DASHBOARD path.
|
|
The fixture would have baked a globe posting to /settings/language with a CSRF field — a form the
|
|
real page never serves. Caught by reading the diff before re-capturing, and independently by
|
|
TestI18nDirectRenderPagesFollowLanguage, which renders through the REAL executeTemplateLang.
|
|
The harness now branches on i18nDirectTemplates.
|
|
D. The first "is the change only the two declared blocks?" measurement compared LINE BY INDEX, and an
|
|
insertion shifts every line below it — so it reported 60 520 changed lines and measured nothing.
|
|
Redone as a real (LCS) diff: exactly TWO change shapes across 106 fixtures, and 5 fixtures
|
|
byte-identical (the two guest share pages and the catch-all — the three that must not change).
|
|
|
|
RELEASE C, second round — after the recovery-page finding
|
|
|
|
E. LIVE CATCH, not planted: /recovery is in the AUTHENTICATED route table, so its reader is the
|
|
HOUSEHOLD — but release C's first draft gave it the anonymous globe, which sets a cookie langFor
|
|
deliberately ignores once there is a session. The button would have done NOTHING. Found by the
|
|
live probe reporting `/recovery globes: 0` (302 to /login) and then reading the route table.
|
|
Fixed: executeTemplateLang branches on hasSession — household form with CSRF, or visitor form
|
|
without. Two tests and the parity harness now carry the same branch.
|
|
F. The per-session CSRF token cannot be a fixture value. Blanked on both sides of every parity
|
|
comparison, exactly as relative ages already were; what stays pinned is that the field is THERE
|
|
and WHICH form it sits in — which is the half that says whether the globe writes the household's
|
|
setting or the visitor's cookie.
|