Fixed
A failed database dump no longer produces a silent, corrupt backup. The old loop piped the dump into gzip and only checked gzip's exit status, so a dump that failed halfway (database down, wrong password, disk full) still left a small .gz that looked like a backup. The loop now runs with pipefail, logs Database backup OK: <file> (<bytes> bytes) or Database backup FAILED per cycle, keeps a failed dump as <file>.failed for diagnosis, and prunes only its own files. Retention 0 disables pruning instead of deleting everything.
Added
CI now waits for the first backup cycle and proves the produced archive is readable and carries a real dump header (plus a readable tar.gz for the data backup where the stack has one).
Upgrading
git pull and docker compose up -d (only the backups container is recreated). Existing backup files are untouched and keep their names. Point your monitoring at the backups container log: a FAILED line is the signal.
Full details in CHANGELOG.md.