--- paths: ["internal/backup/**", "internal/pbs/**", "internal/pbsdr/**", "internal/dr/**"] --- # Backup, PBS and DR `internal/backup/` is the vzdump runner, restore-test scheduler and report store. `internal/pbs/` is the fingerprint-pinned PBS-API client plus the verify maintenance loop. `internal/pbsdr/` and `internal/dr/` carry the DR tier and recipe halves. ## The three PBS laws 1. **Set-only.** `pvesm remove` **DELETES the encryption key**. Re-apply configuration; never remove and re-add a PBS storage to change it. 2. **Secret on stdin.** A token secret is passed on stdin, never as an argv the process table shows. 3. **Verify the pin BEFORE consuming the secret.** A fingerprint check after the secret has been sent protects nothing. ## Verify is server-side, and its default skips the work The agent drives verification **remotely** via the PBS API; `proxmox-backup-client` has **no** verify subcommand. `POST .../verify` defaults to **`ignore-verified=true`, which SKIPS already-verified snapshots** — send `ignore-verified=false` to actually re-read and detect corruption. A verify that skipped everything reports success. ## Presence is not success A timestamp recording an **attempt** is not evidence of a **result**. Where a status field travels beside a timestamp, the verdict must consult **both** — or the timestamp must record 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 changes with it. Leaving a message reading `last run 8h ago` while alarming on a six-day-old **success** turns a true alarm into one the operator dismisses. ## Prune is server-side now `DatastoreBackup` carries **no** `Datastore.Prune`. Boxes set `keep_last: 0` and the off-site endpoint runs the prune jobs. **Box tokens stay write-only — never widen that grant** (R-89).