Files
felhom.eu/documentation/audits/day-2026-10-08/design-R-79.md
T

58 lines
4.7 KiB
Markdown

# R-79 — health issue and warning text on the household's pages and mail: a one-page design (2026-10-08)
**Status:** design only. Read in source today (controller `main` a0370b4ed8ef, hub `main` b2dce901b23f). Architecture
document: `architecture/10-localisation.md` (§9 „compared, not shown", §10.1 „on the wire = not translated",
§10.6b residue table).
## The row is half stale — what moved since it was filed
The row (filed 2026-07-26) says „every producer is English" and asks for a spike to pick the seam. **The seam was picked
and built** by R-516 item 10 (controller, after 0.252.0): the wire text stays frozen (`internal/monitor/wire_golden_test.go`)
and each entry carries a parallel `MsgRef` (bundle key + args) that the dashboard banner renders in the household's
language (`internal/monitor/healthcheck.go:28-35, 73-86`; `internal/web/alerts.go:238-279`, `MessageKey`/`MessageArgs`
rendered by `GetAlerts(lang)`). That is the render-boundary seam, and it is the right one: the hub report keeps its bytes.
**Done (key attached, pinned by `internal/monitor/r516_resource_msgs_test.go`):** all 7 resource entries —
system/data disk high + critical, memory, CPU, temperature (`healthcheck.go:357-441`).
**Still verbatim on the household's banner (zero `MsgRef`):**
| producer | `healthcheck.go` | wire text | what a household sees |
|---|---|---|---|
| Docker unreachable | 138 | `Docker: %v` (English) | English in both languages |
| protected container down | 157 | `Protected container not running: %s` (English) | English in both languages |
| storage almost full (issue) | 170 via `checkStoragePaths` 336 | `issueFmtStorageAlmostFull` (Hungarian, frozen) | Hungarian for an English household |
| storage unavailable / not separate / usage high (warnings) | 173 via 322, 328, 338 | `warnFmtStorage*` (Hungarian, frozen) | Hungarian for an English household |
(The disconnected-drive warning is already replaced by its own banner, `alerts.go:254-261`.)
**The mail half, not covered by R-516:** `health_critical` is customer-on by default
(`controller internal/settings/settings.go:635`). The controller sends `HealthDetails{issues, warnings}` as the event's
details (`internal/notify/notifier.go:139-144, 383-396`). The hub's customer mail localises the headline
(`mail.event.health_critical`) but then appends the **raw details JSON** as „- Megjegyzés: {…}"
(`hub internal/notify/templates.go:187-189`, called from `dispatcher.go:331, 880`). So the household's mail carries
`{"previous_status":"ok","current_status":"fail","issues":["Protected container not running: cloudflared"]}`.
## Options
| | What | Costs | Risk |
|---|---|---|---|
| **A** | Dashboard only: give the 6 remaining producers a `MsgRef` (`checkStoragePaths` returns a parallel `[]MsgRef`); 6 hu+en keys whose Hungarian equals today's text. | ~2 h, controller only. | None on the wire (the wire golden stays green by construction). |
| **B** | A + mail: the hub stops appending the raw details JSON to the CUSTOMER mail of `health_degraded` / `health_critical` / `health_recovered` (operator mail unchanged); the household's mail says what the headline says and points to the dashboard, where A shows the list in its language. | A + ~1 h hub (one set + one test). Needs a hub release. | The household loses a list it could not read anyway; the operator keeps it. |
| **C** | A + translated list in the mail: details carry `issue_keys` [{key,args}] and the hub renders them from its own bundle. | Two-repo, ~1 session; the hub must hold copies of controller keys (two producers, one sentence — the R-516 trap). | Drift between the two bundles. |
**Pick: A now, B after the operator's word.** A is a small, decision-free fix in the shape R-516 item 10 already set.
B is the cheapest honest mail; C buys a translated list at the price of a second copy of every sentence.
**First slice (A), with its red test:** extend `r516_resource_msgs_test.go` with a case per remaining producer
(`checkStoragePaths` with a fake unavailable / not-separate / >90 % path; the Docker and protected-container issues via
their seams) asserting (1) the wire text is unchanged byte for byte and (2) the entry carries its key. Red-proof: drop one
`MsgRef` → the case fails and the `internal/web` banner test shows the wire text. The i18n Go-parity gate
(`scripts/i18n_go_parity.py`) checks the Hungarian values equal the frozen literals.
## One question for the operator
**May the household's „system health" e-mail stop showing the raw technical note, and send the household to the
dashboard for the list instead?** *If you do nothing:* A ships alone; the dashboard is right in both languages, and the
mail keeps its note — a line of English inside curly brackets — as it does today.