A Backup Is a Claim Until a Restore Checks It
In short
- Each verification tier caught what the one before it couldn’t: 34 files matched their checksums and didn’t open, and a hash diff flagged a clip on a failing disk sector while SMART said “Verified”.
- Giving every store a failure scenario put my riskiest single point in an Apple account. The AI agent that ran the checks counts as a reader of the data.
- For the off-site copy I compared four setups and picked Arq to Backblaze B2: encrypted on the Mac, in an account apart from my email, for about a dollar a month.
- A restore test brought 760 MB back from B2 in 12 seconds, and every file matched the checksum recorded when it was first saved.
A lot of my career has been databases and streaming systems, where nothing ships without replication, a tested restore and an alert when a backup goes stale. In September I put my own storage through the same audit, with four rules carried over from that work:
- Every place data lives gets a row and a failure scenario.
- A copy counts as a backup only after a check, in three tiers: count the files, hash them, open them. Each tier catches what the one before it can’t.
- A backup that falls behind raises an alarm.
- The AI agent doing the work counts as a reader of the data.
Every store gets a row and a failure scenario
The inventory is a TOML file with a row for the Mac, the external drives, iCloud, Google, GitHub and the agent transcripts. Each row says what I lose if the Mac dies, if the house burns, if an account locks me out, and a script renders the file as a page organised by failure.
Written out that way, the riskiest single point was an account. With Optimize Mac Storage on, the Mac keeps photo originals only for what fits, and the rest of the library lives only in iCloud. Advanced Data Protection was on, so Apple holds no key and can’t recover the account for me. Protecting the account is half the fix. The other half is a copy outside it.
That copy is a quarterly export of originals to a local drive with osxphotos, which remembers what it has exported, so later runs copy only new photos. The first run pulled 25 Mbit/s on a line that tested at 909. Photos downloads each missing original from iCloud one at a time, and the wait per item dominates.
Verification runs in three tiers: count, hash, open
Each tier costs more than the one before. A count against a manifest is cheap. I checked the first Time Machine backup by mounting the snapshot read-only and recounting its files. A count can’t see a truncated file. A hash can’t see a file that was broken before it was copied.
A hash diff caught a failing sector while SMART said “Verified”
A drive of video was supposed to have a full copy on a second drive. A cheap dual-bay dock can’t run two 3.5-inch drives at once (the second drops off the bus), so the comparison ran one drive at a time: hash every file into a manifest on the Mac, swap drives, hash again, diff the manifests. One night per drive.
Every file matched but one, a 252 MB clip, and the overnight pass had read it end to end. The next morning, copying it failed with an I/O error 76.5 MB in, twice, at the same byte. The drive’s SMART summary still said “Verified”. I let the clip go. The diff turned an unknown into one known loss, and without it I couldn’t have said which of the other files were safe.
34 files matched their checksums and didn’t open
An old SSD was the obvious Time Machine disk, but it held photos and video I wanted to keep. Before erasing it I copied it twice and checked both copies against a SHA-256 manifest. Every file matched. Then every file was opened: each image decoded, each video played through, each document parsed. 34 failed.
The copies matched the source by hash, so the damage was on the original drive, probably for years. Nobody had opened those files since they were written. The drive was then erased as encrypted APFS and became the Time Machine disk.
The agent counts as a reader of the data
An agent did most of the work: it measured the drives, wrote the inventory, built the page and ran the exports. Everything it opens goes to the model provider and is kept under their retention terms, and it also lands in a transcript on the Mac that I keep.
So the folders with personal documents are ask-first: each read needs my approval. The most sensitive files moved into an encrypted disk image, hash-checked before the originals were deleted, and the image is off-limits because mounting it takes a password only I type.
At first it didn’t. When I opened the image to test it, it mounted without a prompt. macOS had saved the password to the login keychain when I created the image, so the encryption protected the files from everyone except whoever sits at my unlocked Mac. When the agent tried to read the keychain entry to find the saved password, its own permission check refused the command as credential exploration, and I did that step by hand. The entry was in Keychain Access (my first search looked in the newer Passwords app and missed it). Deleting it brought the prompt back.
Off-site backup costs about a dollar a month; choosing it was the work
Every important store now has two copies, and both sit in the same room. The failure scenarios set what the off-site copy has to cover:
- Site loss (fire, theft): a copy in another building.
- Deletion and ransomware: dated snapshots, so I can restore a folder as it was last Tuesday. A synced folder like iCloud Drive or the Google Drive app copies the deletion too.
- Account loss: outside the account that holds my email.
- Provider breach: encrypted on the Mac, with a key only I hold.
- Recovery: an hourly recovery point, and a restore I can run on a new Mac without a terminal.
The off-site set is documents, scans, project data and the agent transcripts. Video stays out. I checked four options on October 10:
| Option | Cost at 100 GB | Who holds the key | Catch |
|---|---|---|---|
| Arq 7 to Google Drive | $59.99 once, plus Google’s 2 TB plan at $9.99/month | me | Google quota fixes in Arq’s release notes in 2021, 2023 and 2024 |
| Arq 7 to Backblaze B2 | $59.99 once, plus about $0.70/month ($6.95 per TB) | me | two vendors to keep paying |
| restic or Kopia to B2 | free software, plus about $0.70/month | me | restic has no app, so I schedule it and restore from a terminal; Kopia has an app but is still at version 0.23 |
| Backblaze Personal Backup | $99/year, unlimited | Backblaze, unless I set a private key | with the default 30-day history, a drive left unplugged for 30 days may be removed |
Google Drive was the easy pick, and it fails the account requirement: one lockout takes the email and the backups together.
Paying buys usability, not safety. Encrypted data in B2 is as safe under restic, which has shipped since 2015, as under Arq. Arq comes from a small company, Haystack Software, but its data format is published, so the backups stay readable if the company goes away. The $60 buys a restore I can click through on a new Mac without a terminal or an agent.
The tool choice is reversible: switching costs a re-upload, about a day. Losing the encryption password is permanent, because nobody can reset it, the vendor included.
I picked Arq to B2. The weak point turned out to be the Backblaze account. Its two-factor codes went to Gmail, so anyone in my Gmail could get in and delete the backups. It uses an authenticator app now, and I skipped Sign in with Google for the same reason.
A backup tool uploads each chunk once and keeps every version
An Arq snapshot is a complete list of every file and the chunks it is made of, but each chunk uploads once. Arq names a chunk by a hash of its contents and skips any chunk the bucket already holds, so after the first upload an hourly run sends 15 to 45 MB. Old snapshots cost little, because they share chunks with the new ones.
| Arq 7 | restic | Kopia | |
|---|---|---|---|
| Where chunks split | not published (Arq 5 used a rolling checksum) | content-defined (Rabin), about 1 MiB average | content-defined (buzhash) |
| Chunk names | hash mixed with a secret salt; formula unpublished | plain SHA-256, kept inside encrypted index files | HMAC with a secret key |
| Encryption | AES-CBC with HMAC-SHA256 | AES-256-CTR with Poly1305 | AES-256-GCM or ChaCha20-Poly1305 |
| Password to key | PBKDF2, 200,000 rounds | scrypt | scrypt |
| Removing old data | after every backup | prune; no backup can finish while it runs |
garbage collection after a safety delay |
Content-defined chunking means an insert in the middle of a file moves only the chunk boundaries near it, so the rest of the file still matches what is stored.
The chunk names matter because the storage provider sees them: a plain hash lets anyone holding the bucket check whether I store a file they already have. Kopia and Arq mix a secret into the name. restic hides the plain hash inside encrypted index files, and its design doc notes the leak that remains. In the B2 console my bucket is numbered folders of randomly named objects, as client-side encryption should look from outside.
Deleting old data is the dangerous step. Expiring a snapshot means finding every chunk no remaining snapshot uses and deleting only those. Get it wrong and a later restore is missing pieces. restic stops backups while it prunes, and Kopia waits a safety period before deleting.
Then I tested a restore with the same hash tier: five scanned newspapers, about 760 MB, came back from B2 in 12 seconds, roughly 500 Mbit/s, and all five matched the SHA-256 manifest I wrote when the scans first came in. At that rate the whole backup would come back in under an hour. I haven’t timed a full restore, and thousands of small files will go slower than five large ones.
A page goes red when a backup falls behind
The inventory page reads the disks live, so a Time Machine that falls behind turns red without anyone checking. A backup that quietly stopped looks the same as one that is running until the day a restore needs it.
A restore checked the B2 copy once, in October. Nothing checks yet that it is still running, and that alarm is next.