v0.257.0: the app catalog can speak English (R-560, slice 5 Part A)
gates / gates (push) Successful in 25s
gates / gates (push) Successful in 25s
The READ PATH for a second language in `.felhom.yml`. An `i18n: {en: …}` sibling
block inside the same file; `Metadata.For(lang)` merges it FIELD BY FIELD over the
Hungarian, so a missing or blank English field shows the Hungarian one and a
half-translated app is a legal, shippable state.
`For("hu")` is the parsed struct with `I18n` cleared and nothing else — measured
against all 53 real catalog files, copied into `internal/stacks/testdata/catalog/`.
Lists replace whole; every other list is matched by its own key, never by position.
`For` never writes through the receiver: the metadata is the stack manager's, shared
by concurrent requests, and an in-place merge would leak one household's language
into another household's page.
Pages reach catalog copy only through `LocalizeStacks`/`LocalizeStackPtr`/`MetaFor`,
and `TestNoDirectMetaCopyReadOnPages` keeps a named, reasoned allow-list of every
direct `.Meta.<copy>` read in `internal/web` so the NEXT page to read one fails the
suite instead of quietly rendering Hungarian to an English household.
Eight red-proofs. Two of them convicted a hollow TEST rather than the code: a struct
copy shares its slices' backing arrays, so the obvious DeepEqual mutation check
passed a deliberately broken merge; and a one-entry fixture cannot tell key matching
from position matching. Both rewritten, both then seen to fail.
MinAgent: 0.131.0 (unchanged). Older controllers are unaffected — `LoadMetadata`
uses non-strict `yaml.Unmarshal`, so a pre-0.257.0 box drops the whole block.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -1,3 +1,52 @@
|
||||
## v0.257.0 — the app catalog can speak English (2026-09-20, R-560 slice 5 Part A)
|
||||
|
||||
**MinAgent: 0.131.0** (unchanged).
|
||||
|
||||
The last Hungarian an English household meets on the dashboard is the text that comes from the app
|
||||
catalog: each app's one-line description, its tagline, „mire jó" list, „első lépések", the labels and
|
||||
help lines under every install setting, the prerequisites. 1 032 strings across 53 apps. This release
|
||||
is the READ PATH for their English twins; the twins themselves arrive in catalog pushes.
|
||||
|
||||
**The format** (`10-localisation.md` §7, now measured rather than proposed). A sibling block inside
|
||||
the SAME `.felhom.yml`, so a reviewer sees one app whole:
|
||||
|
||||
```yaml
|
||||
description: "Titkosított jegyzet és szöveg megosztás"
|
||||
i18n:
|
||||
en:
|
||||
description: "Encrypted note and text sharing"
|
||||
```
|
||||
|
||||
- **`Metadata.For(lang)`** (`internal/stacks/metadata_i18n.go`) merges FIELD BY FIELD. An English
|
||||
field that is absent — or blank — shows the Hungarian one, so a half-translated app is a legal,
|
||||
shippable state. That is what makes the catalog batches safe to push one at a time.
|
||||
- **`For("hu")` is the parsed struct with `I18n` cleared**, measured against all 53 real catalog
|
||||
files in `internal/stacks/testdata/catalog/` (`TestMetaForHuIsIdentity`). The Hungarian product
|
||||
cannot be changed by the presence of a translation.
|
||||
- **Lists are replaced whole; everything else is matched by ITS OWN KEY** — `deploy_fields` by
|
||||
`env_var`, options by `value`, `optional_config` groups by `match_group`, integrations by
|
||||
`target`, data paths by `path`. Position matching would mistranslate silently the first time a
|
||||
Hungarian field is inserted above another.
|
||||
- **`For` never writes through.** Metadata lives in the stack manager's cache and is shared by
|
||||
concurrent requests; an in-place merge would leak one household's language into another's page.
|
||||
- **Pages reach copy only through `LocalizeStacks` / `LocalizeStackPtr` / `MetaFor`**, and
|
||||
`TestNoDirectMetaCopyReadOnPages` keeps a named, reasoned allow-list of every direct `.Meta.<copy>`
|
||||
read in `internal/web`, so a NEW page that reads catalog copy off the manager fails the suite
|
||||
instead of quietly rendering Hungarian.
|
||||
- Two copy producers sit in packages that have no request and therefore no language — the
|
||||
integration rows and the initial-credentials note. Both are re-taken from the localised metadata
|
||||
in the handler; identical bytes for Hungarian.
|
||||
- **An older controller is unaffected**: `LoadMetadata` uses non-strict `yaml.Unmarshal` (this repo
|
||||
constructs no `yaml.Decoder` at all, verified), so a pre-0.257.0 box drops the whole `i18n:` block.
|
||||
That is what lets a catalog push reach the entire fleet ahead of the floor raise.
|
||||
|
||||
**Eight red-proofs**, each seen to fail and then revert: a mutated hu branch; deploy fields matched
|
||||
by position; a blank English string winning over Hungarian; the defensive copy removed; optional
|
||||
config, integrations and data paths matched by position; the untranslated half reaching the page.
|
||||
**Two of them found a hollow test rather than a bug** — a struct copy shares its slices' backing
|
||||
arrays, so the obvious `DeepEqual` mutation check passed a deliberately broken merge, and a one-entry
|
||||
fixture cannot tell key matching from position matching. Both tests were rewritten.
|
||||
|
||||
## v0.256.1 — the push log says whether a household sentence was attached (2026-09-18, R-558)
|
||||
|
||||
**MinAgent: 0.131.0** (unchanged). One log line, no behaviour change.
|
||||
|
||||
Reference in New Issue
Block a user