feat(dev-safety): Phase 5 of #185 — belt-and-suspenders automated backups
Adds scripts/dev/backup.py + snapshot-store.sh + backup-bundle.sh + restore.sh: two independent backup mechanisms, deliberately not either/or.
Suspenders (fast, frequent, local): snapshot-store.sh <repo> — APFS copy-on-write snapshot of canonical's .muse/ only, rotated (default keep 20).
Belt (verified, portable): backup-bundle.sh <repo> — `muse bundle create` over every local branch, immediately `muse bundle verify`'d; a bundle that fails verification is deleted rather than left as a false sense of backup. Also rotated.
restore.sh <repo> --from-snapshot|--from-bundle <name> [--force] refuses to overwrite a canonical repo that currently passes `muse verify` unless --force is passed — CanonicalHealthyError, don't clobber a good copy by accident.
8 tests, written first, all building a REAL scratch muse repo under tmp_path (via the real `muse` binary) — canonical_root/backup_base always point at tmp_path, never ~/ecosystem/muse, matching every prior phase's discipline. Full round-trip for both mechanisms: corrupt an object, confirm `muse verify` catches it, restore, confirm verify passes and every branch's head_commit_id matches pre-corruption state exactly. Plus: rotation keeps only the newest N, restore refuses without force against a healthy repo but proceeds without force when already unhealthy, and bundle restore's diff against the source bundle reports zero new commits.
Real bug found and fixed while building this: `muse bundle unbundle` treats an object as "already present" purely by path existing on disk — it never re-validates content — so unbundling on top of an existing (corrupted) store silently leaves the corruption in place. restore_from_bundle now fully wipes and re-inits .muse/ before unbundling, matching restore_from_snapshot's full-replace semantics, rather than overlaying on top of possibly-bad existing state.
Manually verified against the real ~/ecosystem/muse: snapshot-store.sh succeeded and produced a real, working backup. backup-bundle.sh correctly *failed* — canonical has pre-existing, unrelated corruption (musehub staging #188, now reframed as a recovery investigation per gabriel's fidelity-first directive) that `muse bundle verify` correctly refused to certify. The bundle mechanism's fail-safe (delete rather than keep an unverified bundle) worked exactly as designed. Snapshot backup is unaffected and already has real coverage; bundle backup will start working once #188 is resolved.
Semantic Changes
56 symbols
Files Changed
+5
1173 in snapshot
0 comments
muse hub commit comment sha256:a57e9ca1e385a1e7a0e3e28094bc35799950a3ed7b2421712d6fb7f0e523a4a0 --body "your comment"
No comments yet. Be the first to start the discussion.