# Restore Drill — Task 2.9 — 2026-05-11

Verified Task 2.8's daily DB backup is restorable end-to-end.
Authorized one-time CLAUDE.md exception used to CREATE + DROP a
scratch DB on prod and to write `/tmp/restore-drill` on prod.
Read-only-prod resumes after this run.

## Source zip

- **Origin**: DigitalOcean Spaces, bucket `allgifted-mathapi-backups`,
  key `AllGifted Math API/2026-05-11-06-28-40.zip`
- **Size on Spaces** (= local after download): **2,661,676 bytes** (2.54 MB)
- **Pulled to prod via**: Laravel `Storage::disk('backups')->get()` — proves
  the full backup → restore roundtrip including S3 read auth, not just
  the dump → restore loop.
- The local staging zip that spatie creates during `backup:run` is **not
  retained** after a successful upload (no `local` disk in the
  `destination.disks` list). The drill had to fetch from Spaces.

## Restored payload

- Zip contained one SQL dump: `db-dumps/mysql-api.sql`
- Uncompressed size: **24,319,382 bytes** (≈ 24.3 MB)
- Restored into scratch DB `mathapi_restore_test`
  (`utf8mb4` / `utf8mb4_unicode_ci`)

## Row-count comparison (prod vs scratch)

| Table             | Prod  | Scratch | Delta |
|-------------------|-------|---------|-------|
| `users`           | 331   | 331     | 0     |
| `questions`       | 10024 | 10024   | 0     |
| `attempt_ledger`  | 39    | 39      | 0     |

All deltas zero. Acceptable threshold was `< 50`. The zero-delta result
reflects very low write activity between backup creation (06:28:40 UTC)
and the comparison (~minutes later) — consistent with pre-public-launch
state. Not a sign of restore failure; counts on a high-traffic table
would normally drift a few rows in that window.

## Cleanup (verified)

Trap-on-EXIT ran after the main script:

    DROP DATABASE IF EXISTS mathapi_restore_test;
    rm -rf /tmp/restore-drill

Post-cleanup verification (separate ssh call):

- `SHOW DATABASES LIKE 'mathapi_restore_test'` → empty
- `[ -d /tmp/restore-drill ]` → NO

Both confirm clean exit. Prod returns to read-only state.

## Conclusion

Daily DB backup is end-to-end restorable. Task 2.9 complete.

## Follow-ups (not blocking)

- `/var/www/html/mathapi/.env.bak-pre-task2-bootstrap` from the
  2026-05-11 env-bootstrap session can be deleted now that the daily
  pipeline (backup → restore) is proven.
- Consider adding a `local` disk to `backup.destination.disks` if you
  want a one-host-fail-safe local copy alongside the Spaces upload.
  Trades disk usage for one extra recovery path.
