gabriel / muse public

test_binary_separation.py file-level

at sha256:a · View file ↗ · Intel ↗

History
1 files
1 commits
0 hotspots
0 🧊 dead
0 💥 blast risk
sha256:7 feat: add chess domain plugin (Episode 22 finale) A chess game as a po… · gabriel · Sep 12, 2026
1 """Phase 2 of #185 (musehub staging): verify `muse` vs `muse-dev` are unambiguous.
2
3 These tests inspect *live machine state* (PATH, installed venvs), not
4 fixtures — Phase 2 is literally about fixing this developer's environment,
5 so "red" here means the environment isn't fixed yet, and "green" means it
6 is. Deliberately does not mutate ~/ecosystem/muse's source to prove
7 "live-edit reflected" — doing that would touch the very canonical repo this
8 whole ticket exists to protect. Editable-install classification (via
9 which_muse.classify_muse_binary) is sufficient proof: an editable install by
10 definition loads straight from the source tree, so there's nothing further
11 to demonstrate without risking the object store.
12 """
13 import subprocess
14 import sys
15 from pathlib import Path
16
17 sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts" / "dev"))
18 from which_muse import classify_muse_binary # noqa: E402
19
20 HOME = Path.home()
21
22
23 def _resolve_in_login_shell(command: str) -> str | None:
24 """Resolve `command` in a fresh login shell, following symlinks.
25
26 `command -v` reports the first PATH match verbatim — if that's a
27 symlink (as `~/.local/bin/muse` is, by design), the caller needs the
28 real target to classify, so resolve it here.
29 """
30 proc = subprocess.run(
31 ["zsh", "-lc", f"command -v {command}"],
32 capture_output=True, text=True,
33 )
34 out = proc.stdout.strip()
35 return str(Path(out).resolve()) if out else None
36
37
38 class TestStableMuseResolution:
39 def test_muse_resolves_under_installer_managed_venv(self) -> None:
40 resolved = _resolve_in_login_shell("muse")
41 assert resolved is not None, "`muse` does not resolve at all in a login shell"
42 assert str(HOME / ".local" / "share" / "muse" / "venv") in resolved, (
43 f"`muse` resolved to {resolved!r}, expected it under "
44 f"~/.local/share/muse/venv (the installer-managed venv)"
45 )
46
47 def test_muse_never_resolves_under_the_live_source_checkout(self) -> None:
48 resolved = _resolve_in_login_shell("muse")
49 assert resolved is not None
50 assert str(HOME / "ecosystem" / "muse") not in resolved, (
51 f"`muse` resolved to {resolved!r} — inside the live source checkout. "
52 "This is the exact hazard Phase 2 exists to close."
53 )
54
55 def test_muse_classifies_as_not_editable(self) -> None:
56 resolved = _resolve_in_login_shell("muse")
57 assert resolved is not None
58 result = classify_muse_binary(resolved)
59 assert result["editable"] is False
60
61
62 class TestDevMuseResolution:
63 def test_muse_dev_resolves_and_is_editable(self) -> None:
64 resolved = _resolve_in_login_shell("muse-dev")
65 assert resolved is not None, "`muse-dev` does not resolve — Phase 2 not yet applied"
66 result = classify_muse_binary(resolved)
67 assert result["editable"] is True
68 assert result["source_root"] == str(HOME / "ecosystem" / "muse")
69
70 def test_muse_and_muse_dev_are_distinct_binaries(self) -> None:
71 stable = _resolve_in_login_shell("muse")
72 dev = _resolve_in_login_shell("muse-dev")
73 assert stable is not None and dev is not None
74 assert Path(stable).resolve() != Path(dev).resolve()
75
76
77 class TestRedundantResolutionsRemoved:
78 def test_homebrew_muse_shim_is_gone(self) -> None:
79 assert not Path("/opt/homebrew/bin/muse").exists(), (
80 "/opt/homebrew/bin/muse still exists — was a duplicate editable "
81 "shim pointed at the same live checkout, confirmed unused by "
82 "brew (not a formula) or anything else before removal."
83 )
84
85 def test_pyenv_global_site_packages_no_longer_has_muse_installed(self) -> None:
86 proc = subprocess.run(
87 [str(HOME / ".pyenv" / "versions" / "3.14.4" / "bin" / "pip"), "show", "muse"],
88 capture_output=True, text=True,
89 )
90 assert proc.returncode != 0, (
91 "muse is still pip-installed into pyenv's global 3.14.4 site-packages — "
92 "confirmed unused (no Required-by, no .python-version pins) before removal."
93 )