v0.295.0: a box that was off at its backup time catches up once (R-871, decision 109); the missed-backup banner (decision 110); a late daily timer after a host suspend is skipped
gates / gates (push) Successful in 31s

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-05 09:27:16 +02:00
parent e730a629fd
commit 635c33d381
24 changed files with 2074 additions and 18 deletions
+12
View File
@@ -1116,6 +1116,18 @@ Per-app export creates a self-contained `.fab` file (tar.gz, optionally encrypte
The backup system implements a **3-2-1 backup architecture**. Each tier is a **complete,
self-sufficient backup** — any single tier can fully restore an app.
**A box that was off at its backup time catches up (v0.295.0, R-871, `09` decisions 109–110).**
`internal/nightchain`. The night ledger (`<data>/night-ledger.json`) records when each nightly backup leg (database
dump, second copy, off-site copy) last ran to its end. On a controller start or a host resume, a leg that missed its
last scheduled time is made up ONCE, 15 minutes later, in the night's order — backup legs only, never the app-update
leg or a Docker step. Several missed nights are one catch-up; a scheduled leg and a catch-up never overlap; the
whole-guest backup and the catch-up wait for each other. A daily job whose timer fires over 60 minutes late (a host
suspend) is skipped, not run late. The household gets one timeline line (`backup_catchup_done`).
**The missed-backup banner:** when the last daily backup is over 26 h old, every page says when it was, that the box
was off at the backup time (from the metrics record, one sample a minute), and suggests a time when the box is usually
on — it never changes the time itself. Closing it lasts until the next missed backup time; a successful night removes
it. Design: `felhom.eu/documentation/architecture/07-backup-architecture.md` §6.1.1.
**The restore carries the customer's own previous answers (v0.217.0, R-351).**
`internal/backup/offbox_placement.go`. Every recovery unit's `manifest.json` records `drive` and
`namespace_root`, and its `compose/app.yaml` records `SUBDOMAIN`/`DOMAIN`. Until v0.217.0 nothing read