Files
felhom-controller/REPORT.md
T

5.2 KiB

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

ClassifyOffsiteFailurequota / 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:<user>@<host>:<path> 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 <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 recordTier2SuccessrecordTier2Failure 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.