v0.253.0 — errors carry the key of the sentence they are (R-557 slice 2 release B)
gates / gates (push) Successful in 24s
gates / gates (push) Successful in 24s
179 Hungarian sentences were built deep inside a package with fmt.Errorf and printed by whoever caught them: too late to translate where they are shown, too early where they are made. Every one now carries its key across that gap. ZERO Hungarian error literals remain. util.MsgError does three things at once, each earned: - Error() is the Hungarian, byte for byte, so every un-converted printer is unchanged; - errors.Is answers for the kind AND for a wrapped cause (KindErrorf dropped the cause); - an error ARGUMENT renders recursively, so "formázás sikertelen: %w" translates whole. A foreign error — restic, docker, ssh, the stdlib — prints verbatim. It is not ours. 76 display sites go through errText, and TestNoErrErrorInPageOutput convicts any that do not. memoryVerdict returns an error rather than a sentence, so the deploy's 409 and the household's language come from one value; UpdateRefusal gained a Cause to carry it. Plurals, one rule, stated once: a key with .one/.other takes its COUNT first. Not a per-call-site flag — the producer somebody forgot would read "3 app is not running". The guard caught a real key collision (alert.deadapp.one) the day the rule landed. TWO DEFECTS FOUND IN MY OWN TOOLING, recorded rather than quietly fixed. The bulk converter silently dropped multi-line concatenations, damaging 7 producers — and the parity gate could not see it, because every surviving fragment WAS a real base literal while the CALL had lost text; two behaviour tests caught it. And the counting script was case-sensitive, so it said "0 left" while five remained. 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:
@@ -1,6 +1,7 @@
|
||||
# REPORT — localisation slice 2, release A (controller v0.252.0, R-557)
|
||||
# REPORT — localisation slice 2, releases A and B (controller v0.252.0 + v0.253.0, R-557)
|
||||
|
||||
**2026-09-18 · base commit `736f54b49610` (v0.251.0) · MinAgent 0.131.0, unchanged · no hub release.**
|
||||
**Two releases this session: A (the sentences shown now) and B (the 179 error messages).**
|
||||
Architecture read first and named: `felhom.eu/documentation/architecture/10-localisation.md` §1
|
||||
(parity), §2 (mechanism), §5 (gates), §9 (the R-553 signals), §10 (this slice); `07-backup-architecture.md`
|
||||
for what the hub reads from a box; `05-hub-architecture.md` for what the hub composes itself.
|
||||
@@ -113,3 +114,82 @@ new `go-parity`**. `python3 scripts/test_gate_decoys.py` — all 23 decoys behav
|
||||
|
||||
Endpoint-level on demo-hp guest 9201 (no browser on DooPlex — `claude-in-chrome` is not available
|
||||
here). Evidence: `felhom.eu/documentation/audits/i18n-slice2-2026-09-18/A/live/`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
# Release B — v0.253.0: errors carry a key
|
||||
|
||||
**179 Hungarian error literals converted; ZERO remain.** `util.MsgError` carries the key from the
|
||||
package that makes the error to the handler that prints it.
|
||||
|
||||
## 1. The mechanism, and the three things it had to do at once
|
||||
|
||||
| property | why it is not optional | pinned by |
|
||||
|---|---|---|
|
||||
| `Error()` is the Hungarian, byte for byte | every un-converted printer (a log line, a `%v`, a third-party wrapper) keeps printing what it printed. Without it, 179 producers could not be converted before all their printers were. | `TestMsgErrorKeepsKindAndHuText` |
|
||||
| `errors.Is` answers for the kind **and** for a wrapped cause | `KindErrorf` returned the kind alone and dropped the cause; a converted producer usually wraps one | `TestMsgErrorUnwrapsTheCauseToo` |
|
||||
| an error ARGUMENT renders recursively | `„formázás sikertelen: %w"` is a sentence wrapping a sentence; both halves are ours | `TestErrTextRendersAWrappedMessageErrorToo` |
|
||||
| a FOREIGN error prints verbatim | restic, docker, ssh and the stdlib are not ours to translate (R-553's rule) | `TestErrTextFallsBackVerbatim` |
|
||||
|
||||
76 display sites in `internal/web` and `internal/api` now go through `errText`;
|
||||
`TestNoErrErrorInPageOutput` examines 316 display-sink lines and convicts any that do not. A
|
||||
`strings.Contains(err.Error(), …)` is a COMPARISON and stays untouched — the four English ones are
|
||||
R-569.
|
||||
|
||||
`memoryVerdict` returns an ERROR rather than a sentence, so the deploy's 409 and the household's
|
||||
language come from one value; `UpdateRefusal` gained a `Cause` so that error survives the update path
|
||||
to the API.
|
||||
|
||||
## 2. Plurals — one rule, stated once
|
||||
|
||||
**A key that carries `.one`/`.other` forms in a language is a plural key, and its FIRST parameter is
|
||||
the count** (`i18n.Bundle.form`). Hungarian never carries them, so a Hungarian render is unchanged at
|
||||
every count. Deliberately NOT a per-call-site flag: the producer somebody forgot would read „3 app is
|
||||
not running" with nothing to catch it, and the bundle is where a translator works.
|
||||
|
||||
`TestPluralFirstArgIsNumeric` pins that every plural value really takes its count first.
|
||||
`TestNoOrdinaryKeyEndsInAPluralSuffix` pins that the two suffixes stay reserved — **it caught a real
|
||||
collision the day the rule landed** (`alert.deadapp.one`, the ONE dead app, would have been read as
|
||||
the singular of a key that does not exist). Renamed to `alert.deadapp.single`.
|
||||
|
||||
## 3. Two defects release B found in its OWN tooling
|
||||
|
||||
Both are recorded here rather than quietly fixed, because each is a shape that will recur.
|
||||
|
||||
**(a) The bulk converter silently dropped a multi-line concatenation.**
|
||||
`fmt.Errorf("a: "+ "b: %s", x)` kept only `"a: "` and lost the rest with its arguments — 7 producers
|
||||
damaged. **The parity gate did NOT catch it**, and the reason matters: every surviving fragment WAS a
|
||||
real base-commit literal, so the gate's question ("is this text real?") was answered *yes* while the
|
||||
CALL had lost text. What caught it was two behaviour tests that assert the sentence a customer reads
|
||||
(`TestR356_ScenarioC_UndeployedAppIsStillRefused`, `TestR379_ScenarioA_RollbackSucceeds_AppComesBack`).
|
||||
All 7 were rebuilt as joined keys and the six wrong keys pruned from both bundles. **The lesson: a
|
||||
structural gate over the TEXT cannot see a defect in the CALL; only a test that renders the sentence
|
||||
can.**
|
||||
|
||||
**(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" ×2). That is the
|
||||
R-565 shape inside the measuring instrument. Re-measured with `re.I`; the five are converted. The
|
||||
ASCII-fragment search that found them is in §5 below, with its controls.
|
||||
|
||||
## 4. Red-proofs
|
||||
|
||||
Seven planted breaks, each seen to convict and then reverted (full log:
|
||||
`audits/i18n-slice2-2026-09-18/redproofs.txt`, entries 8–14). Plus the two live catches above, which
|
||||
are not red-proofs — nobody planted them.
|
||||
|
||||
## 5. The "no Hungarian error left" claim, with controls
|
||||
|
||||
- **Negative control:** `fmt.Errorf("…qzxvkjq` → 0 hits (the fragment is in no file).
|
||||
- **Instrument works:** the same ASCII search run against the release-B BASE commit finds
|
||||
`sikertelen` 12× in `migrate.go` and `nincs` 7× in `offbox_restore.go`.
|
||||
- **The claim, now:** an ASCII search for `sikertelen|sikeres|telepitve|mentes|nincs|kotelezo|hiba|folyamatban`
|
||||
inside `fmt.Errorf`/`errors.New`, **case-insensitively**, and a separate accented-letter search:
|
||||
**0 hits each**, outside a comment in `internal/util/msgerr.go` that quotes an example.
|
||||
|
||||
## 6. What is left after B
|
||||
|
||||
**705 Hungarian literals**, none of them errors: the country TABLE (113, not on the wire and not
|
||||
translated on purpose), `handler_debug.go` (R-574), the notifier's 27 wire messages (R-558),
|
||||
`funcmap.go`'s two un-overridden helpers (R-572), the text a background run PERSISTS (release C), and
|
||||
the R-570 producer. Release C's default stands: written in the box's language at write time.
|
||||
|
||||
Reference in New Issue
Block a user