"""Phase 2 of #185 (musehub staging): verify `muse` vs `muse-dev` are unambiguous. These tests inspect *live machine state* (PATH, installed venvs), not fixtures — Phase 2 is literally about fixing this developer's environment, so "red" here means the environment isn't fixed yet, and "green" means it is. Deliberately does not mutate ~/ecosystem/muse's source to prove "live-edit reflected" — doing that would touch the very canonical repo this whole ticket exists to protect. Editable-install classification (via which_muse.classify_muse_binary) is sufficient proof: an editable install by definition loads straight from the source tree, so there's nothing further to demonstrate without risking the object store. """ import subprocess import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts" / "dev")) from which_muse import classify_muse_binary # noqa: E402 HOME = Path.home() def _resolve_in_login_shell(command: str) -> str | None: """Resolve `command` in a fresh login shell, following symlinks. `command -v` reports the first PATH match verbatim — if that's a symlink (as `~/.local/bin/muse` is, by design), the caller needs the real target to classify, so resolve it here. """ proc = subprocess.run( ["zsh", "-lc", f"command -v {command}"], capture_output=True, text=True, ) out = proc.stdout.strip() return str(Path(out).resolve()) if out else None class TestStableMuseResolution: def test_muse_resolves_under_installer_managed_venv(self) -> None: resolved = _resolve_in_login_shell("muse") assert resolved is not None, "`muse` does not resolve at all in a login shell" assert str(HOME / ".local" / "share" / "muse" / "venv") in resolved, ( f"`muse` resolved to {resolved!r}, expected it under " f"~/.local/share/muse/venv (the installer-managed venv)" ) def test_muse_never_resolves_under_the_live_source_checkout(self) -> None: resolved = _resolve_in_login_shell("muse") assert resolved is not None assert str(HOME / "ecosystem" / "muse") not in resolved, ( f"`muse` resolved to {resolved!r} — inside the live source checkout. " "This is the exact hazard Phase 2 exists to close." ) def test_muse_classifies_as_not_editable(self) -> None: resolved = _resolve_in_login_shell("muse") assert resolved is not None result = classify_muse_binary(resolved) assert result["editable"] is False class TestDevMuseResolution: def test_muse_dev_resolves_and_is_editable(self) -> None: resolved = _resolve_in_login_shell("muse-dev") assert resolved is not None, "`muse-dev` does not resolve — Phase 2 not yet applied" result = classify_muse_binary(resolved) assert result["editable"] is True assert result["source_root"] == str(HOME / "ecosystem" / "muse") def test_muse_and_muse_dev_are_distinct_binaries(self) -> None: stable = _resolve_in_login_shell("muse") dev = _resolve_in_login_shell("muse-dev") assert stable is not None and dev is not None assert Path(stable).resolve() != Path(dev).resolve() class TestRedundantResolutionsRemoved: def test_homebrew_muse_shim_is_gone(self) -> None: assert not Path("/opt/homebrew/bin/muse").exists(), ( "/opt/homebrew/bin/muse still exists — was a duplicate editable " "shim pointed at the same live checkout, confirmed unused by " "brew (not a formula) or anything else before removal." ) def test_pyenv_global_site_packages_no_longer_has_muse_installed(self) -> None: proc = subprocess.run( [str(HOME / ".pyenv" / "versions" / "3.14.4" / "bin" / "pip"), "show", "muse"], capture_output=True, text=True, ) assert proc.returncode != 0, ( "muse is still pip-installed into pyenv's global 3.14.4 site-packages — " "confirmed unused (no Required-by, no .python-version pins) before removal." )