# REPORT — R-101 + F-DIAG: the customer must not be told a failed backup is a copy (v0.182.0) (2026-07-28) **Overwritten** per the standing rule. Controller **v0.181.0 → v0.182.0**. Full arc incl. Phase 0, the F-OPS runbook and the rendered dialogs: `felhom.eu/REPORT-r101.md`. ## Baselines (reconfirmed, not copied) `felhom-controller 3db8bfb` = origin/main, clean; 0.181.0 live on both boxes; hub 0.80.0 ready 1/1. ## R-101 — misinformation at a decision point, not an alarm bug `Tier2LastRun` is the ATTEMPT clock (`recordTier2Failure` writes it too) and it was rendered as „Legutóbbi másolat" in the **restore confirm dialog**. The restore it guards fills in MISSING files without touching existing ones — so a customer whose Tier-2 had been failing was told a copy existed from last night, restored, and silently received **older** files while believing they were recent. No error, no signal, and the customer's own reason for restoring quietly defeated. `CrossDriveBackup` gains `LastSuccess` (the offsite anchor's rule and shape, not a second implementation) plus `SuccessTracked`, which distinguishes "predates the anchor" from "has one and it is empty". That marker is not optional: **all 7 Tier-2 rows on the fleet** were pre-anchor at deploy, so without it every customer would have been shown „Még nincs sikeres másolat" at once. Legacy rows migrate truthfully on first touch — an `ok` row adopts its time, an `error` row seeds nothing. Three dishonest render sites fixed; the main configured branch and the shares surface were already honest. The dialog also stops printing raw UTC RFC3339 — new `fmtTimeStr` gives Budapest-local `2026-07-28 16:40`. ## Part 2 — the copy-site hazard, in the path of Part 1 The three `record*` helpers each built a WHOLE struct literal with two fields re-applied; everything else was zeroed on every status write. Adding `LastSuccess` to that shape would have had `recordTier2Failure` **clear** it — the mirror image of the defect, firing on the first failure. `tier2Update` now copies the existing row and overlays the outcome: **safe by construction**. Sweep: `SetTier2Preference` mutates in place (safe), `SetCrossDriveConfig(name, nil)` is a deliberate delete. ## F-DIAG — six classes, and a leak I caught in my own fix `ClassifyOffsiteFailure` → `quota` / `orphaned` / `no_repo` / `no_units` / `transport` / **`unknown`**, each with its own Hungarian message; unclassifiable says so rather than being folded into a neighbour. The old message was a raw `err.Error()` passthrough carrying `sftp:@:` off the box. My first sanitiser regex-matched `sftp:…` and `user@host` and looked complete — **its own test caught it leaking** on `ssh: connect to host port 23: Connection refused`, a bare hostname in neither shape. It now redacts the target's **actual** host/user/path literally, regex kept as a backstop. ## Red-proofs — all observed failing | # | red-proof | observed failure | |---|---|---| | A | dialog back on the attempt clock | `the dialog does not name the last SUCCESSFUL copy` | | C | gate the restore on `LastRun` | `a tier that has NEVER succeeded still offers a restore` | | D | caution made unconditional | `a HEALTHY tier shows the failed-attempt caution ("nem sikerült")` | | F | clear the anchor on failure | `a FAILED run wiped the success anchor (round 1)` | | + | raw sanitiser | `the repo reference reached the message ("sftp:" leaked)` | F runs the **real** `recordTier2Success` → `recordTier2Failure` sequence; A/C/D **render the production template tree** and assert the string the customer reads. `go build`, `go vet ./...`, `go test ./...` — 27 packages `rc=0`; template-ID and emoji gates OK. ## LIVE on demo-hp — the rendered dialog Failure induced by moving the Tier-2 destination aside and leaving a file in its place, so `mkdir …/recovery-unit` fails. (`chmod` is useless — the controller is root; `chattr +i` is refused in an unprivileged container. Both tried, both reported.) Data only moved, never deleted; restored intact. ``` status=error last_run=14:42:18Z (ADVANCED) last_success=14:40:55Z (HELD) ``` **failed state:** `… Legutóbbi sikeres másolat: 2026-07-28 16:40. Figyelem: a legutóbbi mentési kísérlet nem sikerült, ezért a visszaállított fájlok ennél régebbiek lehetnek.` **healthy state:** `… Legutóbbi sikeres másolat: 2026-07-28 16:43.` — no caution, no tonal change. **legacy state (pre-run):** `Legutóbbi másolat: 2026-07-28 03:30` — today's wording, unchanged. Restored: destination a directory again, 86 MB intact, mode 755, `status=ok`. **demo-felhom is the untouched control** — all 5 rows still legacy, rendering today's way, 15/15 up. ## Deployed `felhom-controller` **0.182.0** on demo-hp and demo-felhom, both `Up (healthy)`. ## NOT yet live-validated (carried forward) - **F-DIAG's classes** — unit-proven; no live failure of each class was induced. - **Scenario C live** — never-succeeded is unit-proven only; no fleet row is in that state and manufacturing one means destroying an app's only Tier-2 history. - **The Tier-2 restore itself** — this arc changed what the dialog says, not what the restore does. - R-100's 48h threshold (injected clock), fault 4, R-99, F-HUB, fault 12, the concurrency overlap.