REPORT: v0.251.0 — R-553 and R-563, the five sites, red-proofs, live evidence
gates / gates (push) Successful in 23s
gates / gates (push) Successful in 23s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -1,110 +1,89 @@
|
||||
# REPORT — localisation slice 1 (R-556): the whole dashboard in English, Hungarian byte-identical
|
||||
# REPORT — controller v0.251.0: nothing decides by reading a Hungarian word (R-553 + R-563)
|
||||
|
||||
**Date:** 2026-09-17 · **Releases:** v0.248.0 (`ff68b0b`, apps and settings), v0.249.0 (`11b790e`, backups),
|
||||
**v0.250.0** (`ac149c2` + `be2efe5`, storage, sharing, sign-in, guest, catch-all, debug, the switch for
|
||||
everyone) · **MinAgent:** 0.131.0 (unchanged) · **Baseline of the slice:** v0.247.0.
|
||||
**Architecture read before any claim:** `felhom.eu/documentation/architecture/10-localisation.md`
|
||||
(updated: §2.2, §2.3, §3 decision 6 SUPERSEDED, §5, §10, §11), `02-controller-module-map.md`.
|
||||
**Evidence:** `felhom.eu/documentation/audits/i18n-slice1-2026-09-17/{A,B,C}/`.
|
||||
**Date:** 2026-09-17 · **Baseline:** `e236dca48653` (v0.250.0) · **Released:** `0194342` → image
|
||||
`gitea.dooplex.hu/admin/felhom-controller:0.251.0` · **MinAgent:** 0.131.0 (unchanged).
|
||||
**Architecture read before any claim:** `felhom.eu/documentation/architecture/10-localisation.md` §1/§9
|
||||
(§9 rewritten by this session), `07-backup-architecture.md`, `02-controller-module-map.md`.
|
||||
**Evidence:** `felhom.eu/documentation/audits/r553-2026-09-17/`.
|
||||
|
||||
## Claims in the prompt that turned out wrong — named first
|
||||
|
||||
1. **Per-page Hungarian line counts** did not reproduce (debug 92 accented lines, not 103; monitoring 48,
|
||||
not 72; others differ the same way).
|
||||
2. **Marker counts of the v0.247.0 pages** — measured layout 105, backups 59, app_info 58, launcher 28;
|
||||
the prompt said 95 / 52 / 48 / 25.
|
||||
3. **"Templates decide nothing by Hungarian wording"** is false: `backups_remote.html` runs
|
||||
`indexOf('Fut')` on its own status text. The prompt's sweep checked only `==`, `===` and `case`.
|
||||
The word stays Hungarian (R-563).
|
||||
4. **The list of unconverted copy omitted `backups_shared` `restore_banner_js`** — it was still
|
||||
Hungarian after v0.247.0; converted in B.
|
||||
5. **"Six direct-render pages"** — confirmed, not wrong: login, claim, recovery, launcher_shared,
|
||||
launcher_share_password, catchall. No seventh `s.tmpl` render exists now.
|
||||
1. **„`internal/system/mounts_linux.go` L176/L194/L199 produce site 3's warnings."** They do not.
|
||||
`h.Warning` from `CheckBackupDestination` never reaches `report.Warnings` — the only producer folded
|
||||
into the health report is `checkStoragePaths` (healthcheck.go). `system/` needed no change at all.
|
||||
2. **„Site 1 matches `required field` … all producers are ours."** **Nothing produces `required field`.**
|
||||
The router matched a phrase no code in this repo writes — a dead arm, removed with the rest.
|
||||
3. **Site 3's condition matched more than the prompt implies.** Of the nine warnings that exist today,
|
||||
exactly ONE matches („Az adattároló … nem külön meghajtón van"): the three patterns are lower-case
|
||||
and every other warning capitalises the word. So the fix had to preserve *one* inline warning, not a
|
||||
family — `WarnKindStorageNotSeparate` does exactly that.
|
||||
4. **Line numbers drifted** as the prompt warned (router.go:478 → the block moved into a new
|
||||
`deployStatusFor`; offbox.go:186/921; alerts.go:208; handlers.go:920/931 → 944).
|
||||
5. **„`errors.New(refusal)` at the memory site"** — correct, and it is the reason the memory refusal
|
||||
could not be pinned by a unit test: `memoryVerdict` reads the HOST's real memory. Its kind is pinned
|
||||
at the source line instead, and the mapping is covered with a translated memory message.
|
||||
6. **Confirmed as stated:** site 2's classifier has exactly one caller; `offbox_handlers.go:132` is a
|
||||
false positive (an `[INFO]` log line); site 5 is the one rendered byte that changes.
|
||||
|
||||
## Per-page table — all 31 templates
|
||||
## The five sites
|
||||
|
||||
Markers = `{{T}}` occurrences today. States = parity fixture cases rendering the page (captured from the
|
||||
unconverted template first).
|
||||
| # | decision | signal added | producer(s) changed | decision changed | test | HEAD-red → fixed-green |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 | deploy HTTP status | `stacks.ErrRequiredField`, `ErrPathMissing`, `ErrNotEnoughMemory`, `ErrAlreadyDeployed` (`deploy_errors.go`) | `deploy.go` 205/311/326/333/245 | `api/router.go` → new `deployStatusFor` | `TestR553_Deploy_DecisionSurvivesWordingChange`, `TestR553_DeployHandlerUsesTheKind`, `TestR553_DeployProducersCarryKindAndKeepTheirWords` | red: every translated row `= 500, want 400/409`; green after |
|
||||
| 2 | off-site failure class | `backup.ErrOffsiteQuota` | `offbox.go` 921 | `ClassifyOffsiteFailure` | `TestR553_OffsiteQuota_{Decision,HeadLine}SurvivesWordingChange`, `TestR553_QuotaProducerKeepsItsWords` | red: translated quota `= "unknown"`, head line „ismeretlen okból"; green after |
|
||||
| 3 | disk-warning placement | `monitor.WarnKind*` + `HealthReport.WarningKinds` / `addWarning` / `WarningKindAt` | `healthcheck.go` `checkStoragePaths` | `web/alerts.go` | `TestR553_StorageWarningsCarryKindsAndKeepTheirWords`, `TestR553_DiskWarningPlacementSurvivesWordingChange`, `TestR553_HubReportWarningsAreUnchangedOnTheWire` | red: translated warning `Inline = false`, and an unrelated warning wrongly moved inline; green after |
|
||||
| 4 | stale „nothing selected" note | `settings.OffboxTarget.LastWarningKind` + `backup.OffboxWarnNoAppsSelected` | `offbox.go` 1053/1095 (+ both clear sites, both copy sites) | `offboxWarningDisplay` | `TestR553_StaleNote*`, `TestR553_WarningKindIsPersistedAndCopied`, `TestR553_OffboxRunRecordsTheKind` | red: translated note shown verbatim; producer without its kind convicted; green after |
|
||||
| 5 | remote-backup poll (R-563) | `data-status="{{.Offbox.LastStatus}}"` | `backups_remote.html` status element | the page's own script | `TestR563_PollStartsFromAttribute` (hu + en), `TestR563_AttributeFollowsTheStatus` | red twice: poll back on the word (both languages), word back inline (English page shows Hungarian); green after |
|
||||
|
||||
| rel | page | markers | states | | rel | page | markers | states |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| A | dashboard | 48 | 4 | | B | backups_restore_wizard | 46 | 5 |
|
||||
| A | stacks | 37 | 1 | | B | backups_escrow | 58 | 4 |
|
||||
| A | logs | 9 | 1 | | B | tier2_config | 23 | 4 |
|
||||
| A | monitoring | 61 | 3 | | B | recovery | 43 | 7 |
|
||||
| A | app_import | 40 | 2 | | C | storage | 162 | 2 |
|
||||
| A | app_export | 30 | 1 | | C | storage_network | 70 | 2 |
|
||||
| A | deploy | 171 | 5 | | C | storage_init | 42 | 1 |
|
||||
| A | settings_system | 94 | 4 | | C | storage_attach | 27 | 1 |
|
||||
| A | settings_security | 58 | 2 | | C | sharing | 74 | 6 |
|
||||
| A | settings_notifications | 34 | 2 | | C | login | 9 | 1 |
|
||||
| A | app_row | 0 (no copy) | via stacks/dashboard | | C | claim | 21 | 4 |
|
||||
| A | meta_badge | 0 (no copy) | — | | C | launcher_shared | 4 | 2 |
|
||||
| A | icons | 0 (no copy) | — | | C | launcher_share_password | 6 | 1 |
|
||||
| B | backups_apps | 97 | 6 | | C | catchall | 4 | 2 |
|
||||
| B | backups_remote | 81 | 12 | | C | debug | 189 | 1 |
|
||||
| B | backups_restore | 78 | 4 | | | **total, all 36 templates** | **1 874** | **106** |
|
||||
**Message bytes:** every producer's sentence is asserted equal to its pre-change string (sites 1, 2, 4)
|
||||
or rendered identically (site 5). `util.KindErrorf` / `KindError` (new, `internal/util/errkind.go`,
|
||||
documented in REUSE.md §1) build the same bytes `fmt.Errorf` did and carry the sentinel for `errors.Is`.
|
||||
|
||||
Bundles: hu 1 587 keys, en 1 590 (plural forms), English gap 0.
|
||||
**External signatures kept, on purpose:** the classifier's restic and ssh arms — `unable to open config
|
||||
file`, `is there a repository at the following location`, `produced no snapshots`, `connection refused`,
|
||||
`connection reset`, `no route to host`, `i/o timeout`, `timed out`, `permission denied`, `host key`,
|
||||
`handshake`, `could not resolve`, `network is unreachable`. We neither write nor translate that output.
|
||||
|
||||
## What release C shipped
|
||||
|
||||
- 11 templates converted; six ASCII-only Hungarian JS fragments the extractor missed, found by eye.
|
||||
- `login`, `claim`, both guest share pages and the catch-all through `executeTemplateLang` (household
|
||||
language, no session CSRF, no escrow reminder).
|
||||
- Title keys for storage, network storage, both wizards, sharing; the pin test for all 17 title keys.
|
||||
- The switch on every dashboard page: the hide condition deleted; 89 layout fixtures re-captured, each
|
||||
proven to equal its predecessor plus exactly one switch form after the version span (89/89).
|
||||
- A correction: the release C cases had invented page titles; they now carry the handlers' titles and
|
||||
the 12 affected fixtures were re-captured from `0555091` (unconverted). Diff: `<title>` and the wizard nav.
|
||||
- `HU_FORMAL_CEILING` 12 → 16 (four more formal forms in unchanged Hungarian).
|
||||
|
||||
## Red-proofs (release C; A and B in their folders) — each seen failing, then passing
|
||||
|
||||
| test | mutation | failure seen |
|
||||
|---|---|---|
|
||||
| `TestI18nParity` | hu `sharing.megosztott_mappak` loses one accent | 6 sharing cases `Hungarian page CHANGED` |
|
||||
| `TestI18nEnglishPages` | en `storage.eleresi_ut` deleted | `Hungarian template copy on the English page … Elérési út` (2 cases) |
|
||||
| `TestI18nParityCoversEveryMarker` | a marker in a branch no case renders | `marker never rendered by any parity case: storage_attach.hiba` |
|
||||
| `TestHandlerTitleKeysMatchHungarianTitle` | hu title reworded; the sharing TitleKey line deleted | `handler title "Hálózati megosztás", but hu.json … = "Hálózati megosztások"`; `page.title.sharing has no handler` |
|
||||
| `TestDirectRenderHandlersFollowLanguage` | all five call sites back on `s.tmpl.ExecuteTemplate` | five rows: `with en saved: … <html lang="en" false` |
|
||||
| `TestI18nDirectRenderPagesHaveNoAdminChrome` | `addEscrowBanner` added to `executeTemplateLang` | `put EscrowBanner / CSRFField into the page data` for every page. The page layer alone stays green under this mutation (the guest template has no slot for the bar) — stated in the test |
|
||||
| `TestLanguageSwitch_EndToEnd` | the v0.247.0 hide condition restored | `a Hungarian household with no ?lang= must see the language switch`; 89 parity cases fail |
|
||||
**The wire:** `internal/report/builder.go` copies Status/Issues/Warnings only; the kinds are internal.
|
||||
Pinned by field-set + byte test, and confirmed live (the health block on 0.251.0 carries exactly
|
||||
`issues, status, warnings`).
|
||||
|
||||
## Gates
|
||||
|
||||
- `go build ./... && go vet ./... && go test ./...` → rc 0 before each commit.
|
||||
- `controller_gates.py --fast` → rc 0 (i18n: English missing 0/0, formal 16/16; retrieval-promise OK);
|
||||
`test_gate_decoys.py` 20/20. Pre-push hook ran on both pushes; no `--no-verify`.
|
||||
`go build ./... && go vet ./... && go test ./...` → rc 0 before each push. `controller_gates.py --fast`
|
||||
→ rc 0. No `--no-verify`. One existing test (`TestClassifyOffsiteFailure_EachCauseIsDistinct`) built the
|
||||
quota error the old way and was adapted to build it as the run does — stated here rather than silently.
|
||||
|
||||
## Live validation (endpoint-level; no browser on DooPlex) — demo-hp guest 9201
|
||||
|
||||
Deployed by hand; **fleet floor NOT raised, no golden.** Startup: `lang=hu … 1874 markers expanded in
|
||||
27.35ms`, `lang=en … 28.37ms` (B: 26.5 / 21.3 ms; A: ~24 / ~20 ms).
|
||||
- **Hungarian 0.249.0 → 0.250.0:** each dashboard page carries one switch form after the version span;
|
||||
removed, 7 of 8 pages are identical; `/dashboard` differs in live numbers and the order of two
|
||||
drive rows. `/login`, `/claim`, catch-all: identical, no switch.
|
||||
- **English:** `POST /settings/language lang=en` → 302; all 11 pages `<html lang="en">`; no accented
|
||||
Hungarian on storage, sharing, wizards, debug, sign-in. Left: catalog taglines, Go-built text.
|
||||
- **Back to Hungarian:** identical to the after fetch apart from live numbers.
|
||||
- **Hub report:** `hu` 16:45:10, `en` 16:46:06, `hu` 16:46:43 (all 0.250.0).
|
||||
- Guest share pages: not exercised live (would create a share link on the household's box); proven
|
||||
through the real route in unit tests.
|
||||
Deployed by hand; **fleet floor unchanged (0.250.0), no golden.**
|
||||
- **Hungarian pages 0.250.0 → 0.251.0:** `/launcher` and `/monitoring` identical; `/backups/remote`
|
||||
identical apart from the new attribute and the poll line (+23 bytes); `/dashboard` differs in live
|
||||
numbers only.
|
||||
- **Deploy refusal:** `POST /api/stacks/adventurelog/deploy` on an already-deployed app → **409 before
|
||||
and after with byte-identical message**; the app kept running.
|
||||
- **Site 5 live:** `id="offbox-status-value" data-status="ok"` and `v.dataset.status === 'running'`.
|
||||
- **Hub:** `health.warnings` `[]` before and after, health keys unchanged.
|
||||
- **Not provoked live, and why:** the 400 refusals (a live probe starts an install), the quota failure
|
||||
(would need a full quota), the stale note (would need clearing the selection), and the disk-warning
|
||||
placement (this box has no storage warning — 0 banner blocks before and after). All four are carried
|
||||
by red-proofed tests.
|
||||
- **A mistake, and what I did:** the FIRST live probe posted an empty value map to `vaultwarden`, which
|
||||
has no empty required field — so the deploy was accepted (202) and the app installed. I stopped it and
|
||||
removed it (with the data volume it had just created) within two minutes, verified no container
|
||||
remained, and rewrote the probe to the 409 form. Nothing else on the box was touched; the standing
|
||||
apps and `bentopdf` were not involved.
|
||||
|
||||
## Teardown
|
||||
|
||||
Machine: box on `hu`, 0.250.0; password, session and header files shredded; fetched pages pulled off
|
||||
and removed; the three fetch/switch scripts (no secrets) stay in `/root`. Host: transfer files removed.
|
||||
Hub: nothing written; DB copy shredded. Nothing provisioned.
|
||||
Machine: guest on `hu`, controller 0.251.0; password file and probe scripts shredded/removed; evidence
|
||||
pulled off before anything was cleaned. Host: transfer files removed. Hub: nothing written; the DB copy
|
||||
shredded. Nothing provisioned.
|
||||
|
||||
## Observations
|
||||
|
||||
1. A page decides its progress poll by reading its own Hungarian word „Fut". **FILED: R-563**
|
||||
2. The retrieval gate's Hungarian stems miss split verbs, exposed by the English translation. **FILED: R-564**
|
||||
3. Six ASCII-only Hungarian fragments reached the English pages with every test green; the English page test sees accented letters only. **FILED: R-565**
|
||||
4. Three page titles built in Go around an app name stay Hungarian in the English tab. **FILED: R-566**
|
||||
5. The two drive wizard pages do not highlight the storage menu group. **FILED: R-567**
|
||||
6. The dashboard's drive-health rows swapped order between two fetches a minute apart. **FILED: R-568**
|
||||
7. The formal-form stem list counts 4 of at least 22 formal forms on the release C pages. **FILED: R-516**
|
||||
8. `r400_debug_routes_test.go` and `debug_route_gate.py` read `debug.html` raw after conversion. **NOT-A-FINDING: they match addresses and identifiers, which never move into a bundle (0 `/api/` strings in either bundle, measured); both stay green and correct.**
|
||||
9. traefik answers an unrouted host itself, so the catch-all page was fetched from the container address. **NOT-A-FINDING: routing of unknown subdomains is traefik configuration by design; the controller page renders when reached, and the method is stated in the evidence.**
|
||||
1. Four more API handlers pick their status by matching ENGLISH internal words (`protected`, `not found`, `not deployed`, `still running`, `not orphaned`). **FILED: R-569**
|
||||
2. The stale-note display keeps a Hungarian-text fallback for boxes that have not run off-site on ≥ 0.251.0, and slice 2 must not translate that producer until it goes. **FILED: R-570**
|
||||
3. The off-site failure classifier and the alert-placement rule are described in no architecture document. **FILED: R-571**
|
||||
4. `required field` was matched by the router and produced by nothing — a dead arm. **NOT-A-FINDING: deleted with the rest of the text chain in this release; nothing to track.**
|
||||
5. The i18n inventory's comparison detector, re-run on the fixed tree, reports one Go compare and one indirect compare. **NOT-A-FINDING: the first is the known `[INFO]` log-line false positive, the second is the deliberate legacy fallback carried by R-570; decoys prove the detector still convicts.**
|
||||
|
||||
Reference in New Issue
Block a user