v0.252.0 — the sentences the program builds follow the language (R-557 slice 2 release A)
gates / gates (push) Successful in 23s

Slice 1 translated the dashboard's markup. The sentences the program BUILDS were still
Hungarian literals in Go, so an English household clicked an English button and was
answered in Hungarian. 226 of them move into the bundle here.

A flash was the hard part: it travels inside the redirect URL and is rendered by a
DIFFERENT request, so it now carries a bundle key plus its parameters. A link minted by
an older controller carries prose and is shown verbatim — never a raw key, never dropped.

Also converted: page data and view-model text, the internal/api JSON answers, the alert
banners (Alert.MessageKey, rendered on the way out of GetAlerts), 237 country names at
display, and the four page titles built around an app name (R-566 closed).

Hungarian is byte-identical, and that is measured rather than read:
scripts/i18n_go_parity.py freezes every Go literal at the base commit (7 467) and refuses
a key whose Hungarian is not that text, byte for byte. Three decoys, each seen to convict.
Its own first version filtered the capture through an ASCII-Hungarian word list and missed
seven real literals — the R-565 class. The filter is gone.

Nothing on the wire moved, and wire goldens now hold it there: the report's health
warnings and every notify event message stay Hungarian, because the hub MAILS the
controller's sentence when it has no entry of its own. Slice 3 (R-558) owns those.

MinAgent: 0.131.0 (unchanged). No hub release needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-18 10:15:56 +02:00
parent 736f54b496
commit 5270bad76e
52 changed files with 10755 additions and 478 deletions
+53
View File
@@ -1,3 +1,56 @@
## v0.252.0 — The sentences the program writes follow the language (2026-09-18, R-557 slice 2 release A)
**MinAgent: 0.131.0** (unchanged). **No hub release needed.** Nothing a Hungarian household reads
changes: every converted sentence is byte-identical to the literal it replaced, measured by a new
gate rather than read, and nothing on the wire moved.
Slice 1 translated the dashboard's MARKUP. The sentences the program BUILDS — flash lines, page data,
the JSON the page's own script reads, the alert banners, the country names — were still Hungarian
literals in Go, so an English household clicked an English button and was answered in Hungarian.
This release moves 226 of them into the bundle and gives them a way to reach the reader.
**The flash line was the hard part.** It travels to the page INSIDE THE REDIRECT URL, so it is
rendered by a different request from the one that wrote it — until now in the language of whoever
redirected. It now travels as a bundle key plus its parameters (`?flash=flash.share.enabled&fa=…`),
and the page renders it. A link minted by an older controller carries prose; that is shown verbatim,
never as a raw key and never dropped (`TestFlashKeyRoundTrip`, including the legacy and the
`<script>` case).
| what | how it reaches the reader now |
|---|---|
| flash lines (8 writers, 8 readers) | a key in the redirect URL, rendered by the page that reads it |
| page data, view-model labels | `s.msg(r, key, …)` / `s.msgLang(lang, …)`; the builders learned the language |
| API answers (`internal/api`) | `r.msg(req, key, …)` — the same helper, one package over |
| alert banners | `Alert.MessageKey` + args, rendered on the way out of `GetAlerts(lang)` |
| 237 country names | `country.<ISO2>`; the cloudflare TABLE is untouched and still validates codes |
| three app-named page titles + the tier-2 one (R-566) | a title key with a `%s`, plus `TitleArgs` |
**What deliberately stays Hungarian, and why.** Anything a HUB reads: the report's `health.warnings`
and `health.issues`, and every `notify` event message — the hub composes the customer's e-mail from
those and falls back to the controller's own sentence when it has no entry of its own
(`FormatCustomerEmail`). Those follow the household's language in slice 3 (R-558). Both are now
pinned by wire goldens (`internal/monitor`, `internal/notify`) so a later slice cannot translate them
by accident. Also untouched: the R-570 producer, and every `fmt.Errorf` (release B).
**The gate that makes "byte-identical" a measurement.** `controller/scripts/i18n_go_parity.py`
freezes every Go string literal at the base commit (7 467 of them, `scripts/i18n_go_base.json`) and
refuses a key whose Hungarian is not that text, byte for byte — reworded, re-punctuated, split or
joined. `scripts/i18n_go_keys.json` records what each of the 426 keys replaced. Registered in
`controller_gates.py`; three decoys in `test_gate_decoys.py`, each seen to convict. It caught a real
defect in its own first version: the capture filtered literals through an ASCII-Hungarian word list
and missed seven („Naponta", „5 percenkent", „Eletjel (Heartbeat)", …). The list is gone; every
literal is indexed.
- `Bundle.Msgf` fills a message's own printf verbs. English reorders with Go's explicit argument
indexes (`%[2]s`) — no second placeholder syntax, and hu.json stays byte-equal to the format string
the code always had, which is what the parity gate compares.
- `s.bundle()` falls back to the embedded `i18n.Shared()`, so a Server built without `loadTemplates`
renders sentences and never a raw key (red-proofed).
- The notifier's test seam moved into `PushEvent`: most producers called it directly, so a recorder
saw nothing from them and "pushed nothing" looked exactly like "pushed an empty message".
- `HU_FORMAL_CEILING` 16 → 18. Two „ön" forms the gate could not see before are now in the bundle,
word for word as the Go code said them. R-516 still owns the words.
## v0.251.0 — Nothing decides by reading a Hungarian word (2026-09-17, R-553 + R-563)
**MinAgent: 0.131.0** (unchanged). **No hub release needed.** Nothing a household reads changes: every