feat(dev-safety): Phase 4 of #185 — disposable sandbox tooling for muse-dev
Adds scripts/dev/sandbox.py + sandbox-refresh.sh + sandbox-run.sh: gives muse-dev's guard rail (Phase 3) somewhere safe to actually be used for real dev work. sandbox-refresh.sh <repo> clones a canonical repo's working tree + .muse/ into a timestamped, disposable copy via APFS copy-on-write (`cp -c -R`) — near-instant, near-zero extra disk until the copy diverges. sandbox-run.sh <repo> -- <args> wraps `muse-dev -C <current-sandbox> <args>`. A `current` symlink tracks the latest refresh; old timestamped clones beyond --keep (default 5) are pruned automatically.
8 tests, written first, all against tmp_path fixtures — never the real ~/ecosystem/muse (matching test_dev_guard.py's discipline). Covers: branch heads match canonical exactly after refresh, the current symlink always points at the latest, rotation keeps only the newest N, a corruption introduced in the sandbox never touches canonical, editing canonical after a refresh doesn't retroactively affect an already-existing sandbox (proving cp -c produced a genuinely independent copy, not a shared/linked view), unknown repo names fail clearly, and sandbox-run.sh correctly wraps the real muse-dev binary (skipped gracefully if muse-dev isn't installed).
Hit and fixed a real argparse gotcha along the way: nargs=REMAINDER swallows earlier flags too eagerly when they appear before the remainder positional in argv, regardless of `--` placement. sandbox.py now splits the muse-dev tail args on the first literal `--` manually instead of relying on REMAINDER.
Manually verified end-to-end against the real ~/ecosystem/muse: refreshed a real sandbox, ran `muse-dev status --json` against it and got identical untracked-file state to canonical, corrupted an object inside the sandbox only, and confirmed via `muse verify-object --all --json` that canonical was completely unaffected throughout.
Unrelated discovery during that manual verification, filed separately as musehub staging #188 (not blocking this phase): canonical's object store already has ~3,010 objects that fail hash verification, independent of anything done here — `muse verify`'s branch-reachability walk reports everything reachable is clean, and the bad objects appear to be a subset of ~9,363 already-unreachable objects, most likely orphaned leftovers from a historical `muse code migrate --force-resign` pass. Needs its own investigation before any `muse gc`.
Semantic Changes
42 symbols
Files Changed
+4
1168 in snapshot
0 comments
muse hub commit comment sha256:f20267508f836150a1df05f57eaba390a49dae7412c1579a2c26beb3dfe94b50 --body "your comment"
No comments yet. Be the first to start the discussion.