---
paths: ["controller/internal/backup/**", "controller/internal/appbackup/**", "controller/internal/recovery/**", "controller/internal/appexport/**", "controller/internal/quiesce/**"]
---

# Backup, recovery units and export — felhom-controller

## Assert the consequence across the whole run, not the mechanism inside one function

The R-181 recovery-unit refusal claimed *"the previous unit is untouched and NOTHING was deleted"*.
*Nothing deleted* held; **untouched was measured false** — the floor was checked ONLY in
`captureAllRecoveryUnits`, while the two dump legs wrote the bulk into the same tree first and
unguarded, so a 182,272 B tar became 2,147,666,432 B under a manifest that had not moved. A full
green suite plus three of its own red-proofs missed it, because every one asserted the mechanism
inside `captureAllRecoveryUnits`.

**The test that catches this class: fingerprint the tree before and after the whole backup run, and
compare.** Full doctrine and the other eight instances: the `felhom-testing` skill.

## Presence is not success

A timestamp recording an **attempt** must never be read as evidence of a **result**. Where a status
field travels alongside a timestamp, the verdict consults both — or the timestamp records only
successes. Ask of any timestamp: *what exactly must have happened for this to be set?* If the answer
is "we tried", it cannot answer "did it work".

**Corollary:** when a verdict changes which field it counts from, the alarm text has to change with
it. `last run 8h ago` while alarming on a six-day-old success turns a true alarm into one the
operator dismisses.

<!--
Two instances. F-CRIT-2: a phantom snapshot's ctime set tier freshness — an aborted 1-byte upload
made the tier look backed up. R-100: LastRun is written on failure, so a nightly-failing offsite
tier kept the staleness clock fresh forever.
-->

## Storage keys and paths

- Never guess a persisted key — it is `offbox`, not `offbox_target` (R-7b).
- `.fab` export/import uses strict segment validation; bundles from controller ≤0.124.0 are hollow.
- Recovery-unit restore and tier-2 copies share `appbackup`'s path primitives — change them there,
  once, not per caller.
