i18n slice 1 release C (controller v0.250.0): R-556 CLOSED, live evidence, R-565..R-568, decision 6 superseded
gates / gates (push) Successful in 23s

- audits/i18n-slice1-2026-09-17/C/: live before/after/en/back on demo-hp (CSRF redacted), hub report
  hu/en/hu, red-proofs, the switch fixture diff (89 of 89), green gate.
- 10-localisation.md: §2.2 executeTemplateLang facts, §2.3 what stays Hungarian + the English test's
  ASCII blind spot, §3 decision 6 SUPERSEDED 2026-09-17, §5 formal ceiling 16 and its under-count,
  English retrieval stems; §10 slice 1 done; §11 decision 6 struck.
- Register: R-556 closed to CLOSED-ITEMS; R-516 extended; R-565 (ASCII-only Hungarian invisible to the
  English page test), R-566 (three app-name page titles), R-567 (wizard nav highlight), R-568 (disk
  rows reorder). 260 -> 263 open.
- Capability map row, STATUS (needs you: the floor delivers the switch).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-17 18:50:16 +02:00
parent bc15153e0f
commit 5b6ade033f
57 changed files with 28747 additions and 22 deletions
+43 -19
View File
@@ -64,11 +64,17 @@ parses it.** Decided by CC in the spike (the starter delegated the choice, §4 1
unchanged.
- **[FACT]** An **undefined** key is left in place, so the set fails to load („function T not
defined") — loud at startup and in every render test (`TestExpandLeavesUndefinedMarker`).
- **[FACT]** Only `executeTemplate` is language-aware (`server.go`). Login, claim, recovery and the
guest share pages render through `s.tmpl` directly and stay Hungarian until their slice.
- **[FACT]** Go-side copy on a converted page: the handler names its title key (`data["TitleKey"]`);
the non-Hungarian sets override the copy-producing funcs `stateLabel`, `timeAgo`, `timeAgoStr`,
`nextRunLabel`, `statusText` from the bundle (`web/i18n_web.go` `localeFuncs`). The Hungarian funcs
- **[FACT]** `executeTemplate` renders dashboard pages in the request's language. Since slice 1
(v0.249.0 recovery, v0.250.0 the rest) the pages outside the dashboard chrome — login, claim,
recovery, both guest share pages, the catch-all — render through `executeTemplateLang`: the language
set and `Lang`, and deliberately NOT the session CSRF fields or the escrow reminder (R-543) that
`executeTemplate` adds. Pinned by `TestDirectRenderHandlersFollowLanguage` (the real routes) and
`TestI18nDirectRenderPagesHaveNoAdminChrome` (reminder genuinely due, absent from the page data of all
six and from the guest page in both languages). No renderer uses `s.tmpl` directly any more.
- **[FACT]** Go-side copy on a converted page: the handler names its title key (`data["TitleKey"]`;
`TestHandlerTitleKeysMatchHungarianTitle` pins each handler's Hungarian literal equal to its hu.json
value); the non-Hungarian sets override the copy-producing funcs `stateLabel`, `timeAgo`, `timeAgoStr`,
`nextRunLabel`, `statusText`, `infraMeta` from the bundle (`web/i18n_web.go` `localeFuncs`). The Hungarian funcs
are not touched; `TestLocaleFuncsHungarianBundleMatchesFuncMap` pins that `hu.json` carries the same
words they return.
@@ -84,14 +90,18 @@ parses it.** Decided by CC in the spike (the starter delegated the choice, §4 1
- **Render blank or raw.** No raw key, no marker, no element empty in English that is not empty in
Hungarian (`TestI18nEnglishPages`).
**[FACT] What stays Hungarian on the English pages, live:** only Go view-model text (the backup-target
banner and offer, the whole-guest tier labels, the update badge „Naprakész") and catalog copy (the
app's tagline, use cases, first steps) — slices 2 and 5. No template copy.
**[FACT] What stays Hungarian on the English pages, live (v0.250.0, all 31 slice-1 templates converted):**
Go view-model text (flash lines, errors, the backup-target banner and offer, the whole-guest tier
labels, the update badge „Naprakész", the catch-all's status sentence), three page titles built in Go
around an app name (logs, deploy, tier-2 settings — R-566), and catalog copy (tagline, use cases, first
steps) — slices 2 and 5. Deliberately left in a template: „Fut…" on `backups_remote`, which the page's
own JS reads (R-563). Evidence: `audits/i18n-slice1-2026-09-17/{A,B,C}/live/`.
**[FACT] Measured limit of the English page test:** it subtracts every string the fixture DATA carries
(catalog copy, handler messages) before looking for Hungarian — so a template word identical to a data
string is masked (the launcher cases pass the nav's „Indítópult" as the page title). The backups and
app cases cover the nav; the limitation is recorded, not fixed.
**[FACT] Measured limits of the English page test.** (1) It subtracts fixture DATA strings before
looking for Hungarian; since slice 1 release A only data strings of ≥ 2 words or ≥ 12 characters are
subtracted, so a one-word template title is no longer masked. (2) **It sees accented Hungarian only.**
An ASCII-only Hungarian word left in a template („mp", „ db", „jelenlegi:", „FIGYELEM:", „, majd a(z)")
passes it on the English page; release C found six such fragments by eye, none by a test (R-565).
---
@@ -126,6 +136,15 @@ yet, which no household has asked for. **Chosen (2)**: it follows rule §1 (noth
and is reversed by deleting one condition in `addLanguageData`. The way back from English is always on
screen.
**[FACT] SUPERSEDED 2026-09-17 by slice 1 release C (controller v0.250.0):** every template is converted,
so the condition is deleted and the switch is on every dashboard page, in both languages. The 89
layout parity fixtures were re-captured and each equals its predecessor plus exactly one switch form
(`audits/i18n-slice1-2026-09-17/C/switch-fixture-diff.txt`); `TestLanguageSwitch_EndToEnd` pins that a
Hungarian household with no `?lang=` sees it. Live on demo-hp: every Hungarian dashboard page equals
its 0.249.0 fetch once the switch form is removed (live numbers aside); login, claim and the catch-all
are unchanged. **A Hungarian household sees it only when the fleet floor reaches 0.250.0** — the
operator's cadence (R-242/R-468); no floor was raised.
---
## 4. Fallback
@@ -153,13 +172,17 @@ bundles. They now judge the page **as rendered in each language** (`controller/s
`controller/scripts/test_gate_decoys.py`.
**[DESIGN] Voice, per language:**
- **hu** — the product speaks in „te". The converted copy carries **6 formal („ön") forms** (R-516).
They are not fixed by a localisation release (§1), so the gate counts them against
`HU_FORMAL_CEILING` = 6 as a ratchet: a new one convicts, fixing one lowers the ceiling.
- **hu** — the product speaks in „te". The converted copy carries formal („ön") forms (R-516). They are
not fixed by a localisation release (§1), so the gate counts them against `HU_FORMAL_CEILING` as a
ratchet: a new one convicts, fixing one lowers the ceiling. The ceiling followed the conversion:
6 (spike) → 10 (release A) → 12 (release B) → **16** (release C). **[FACT] Measured limit:** the stem
list is short — on the release C pages it counts 4 formal forms, while a wider list („írja be",
„adja meg", „válassza", „biztosan eltávolítja", „engedélyezze", …) finds at least 22 keys (R-516).
- **en** — second person, plain: no „please", no „kindly".
**[FACT] Not yet per-language:** the retrieval-promise gate's stems are Hungarian only — an English
retrieval promise is unscanned (in R-556). The hub copy gate and the catalog have no language concept
**[FACT] The retrieval-promise gate scans English too** since slice 1 release A (`EN_PATTERNS`,
`ALLOWLIST_EN`, decoys). Translating exposed that its Hungarian stems miss split verbs („állíthatók
vissza") — R-564. The hub copy gate and the catalog have no language concept
(`scripts/hub_copy_gate.py` stems end in a Hungarian character class; `catalog_gates.py` checks no copy).
---
@@ -231,7 +254,7 @@ session). Each slice ends with the parity gate green for every page it touched.
| slice | row | what | proves | cost |
|---|---|---|---|---|
| 0 (done) | — | mechanism, 3 pages + layout, setting, report field, gates | Hungarian unchanged by measurement; English reachable | spent |
| 1 | R-556 | the other 31 dashboard templates (~1 500 strings, 600 of them JS), parity fixtures per page; switch shown to everyone; English retrieval stems; the extractor's ASCII word list reviewed per page | the whole dashboard in English with Hungarian byte-identical | 12–16 h, three releases |
| 1 (done, v0.248.0–v0.250.0) | R-556 | the other 31 dashboard templates (~1 500 strings, 600 of them JS), parity fixtures per page; switch shown to everyone; English retrieval stems; the extractor's ASCII word list reviewed per page | the whole dashboard in English with Hungarian byte-identical | 12–16 h, three releases |
| 2 | R-557 (after R-553) | Go-side customer strings: 947 shown + 184 errors; flash-in-URL → keys; country names; alert texts | a page's server messages follow the language | 16–20 h |
| 3 | R-558 | hub: per-customer language at creation; `configgen` renders it; `customerMessages` (39), the 5 lifecycle mails and the self-bind page in English; dispatcher reads the reported language | a household's e-mails arrive in its language | 6–8 h, one hub + one controller release |
| 4 | R-559 | console banner (34 lines, console-font limits) and the download page | an English household meets English from the first boot screen (in scope — ruling 1b) | 4–6 h + an ISO train |
@@ -256,7 +279,8 @@ These are rulings, not proposals. Anything specced against a different assumptio
### Decided by CC in the spike — operator may reverse
5. **Mechanism (b2)** — §2.1.
6. **Switch hidden while only three pages are English** — §3.
6. ~~**Switch hidden while only three pages are English** — §3.~~ **Superseded 2026-09-17** by slice 1
release C (v0.250.0): every template converted, switch shown to every household (§3).
### 2026-09-17 (evening) — the two open questions, ruled