volt: spark profile-health suite, 9 cells, and the lane gate collects them (Q81) -- spark/CHECK ran 0 unittest tests before this commit and prints 'Ran 9 tests / OK' after; every cell is red against a named mutant (M1-M8, measured), M0 control 0/9; the new CHECK leg resolves its own directory from $0, verified by sabotage: host tree rc 0, sabotaged copy rc 12
This commit is contained in:
1 parent
bc8ccb1bd2
commit
829268f15d
2 files changed
+150
No files matched your search
@@ -27,5 +27,13 @@ python3 --version 2>&1 | grep -q "Python" || exit 10
|
||||
# Check git commit pushed
|
||||
git -C /root/troupe-standup rev-parse ed959f0 >/dev/null 2>&1 || exit 11
|
||||
|
||||
# Q81: the profile-health suite. One cell per graded behaviour (9 cells at 2026-10-26).
|
||||
# Resolves its own directory from $0, so this leg grades THIS checkout, not a host path.
|
||||
SPARK_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
suite_out="$(python3 -m unittest discover -s "$SPARK_DIR" -p 'test_hermes_profile_health.py' 2>&1)"
|
||||
suite_rc=$?
|
||||
echo "$suite_out" | tail -3
|
||||
[ "$suite_rc" -eq 0 ] || exit 12
|
||||
|
||||
echo "VERIFIED"
|
||||
exit 0
|
||||
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Cells for wizard-work/spark/hermes_profile_health.py (Q81).
|
||||
|
||||
Every cell drives the tool as a subprocess and grades its exit code, so the thing
|
||||
under test is the CLI contract (0 clean / 1 named faults / 2 ungradable), not an
|
||||
internal function. Fixtures are built in a fresh temp dir per cell; nothing here
|
||||
reads or writes a real profile home, and no host path is referenced: the tool is
|
||||
located from this file's own directory.
|
||||
|
||||
Run: python3 -m unittest discover -s wizard-work/spark -p test_hermes_profile_health.py
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
TOOL = Path(os.path.dirname(os.path.abspath(__file__))) / "hermes_profile_health.py"
|
||||
DIRS = ("skills", "plugins", "cron", "memories")
|
||||
GOOD_CONFIG = "model: deepseek-v4.1-flash\nprovider: deepseek\n"
|
||||
|
||||
|
||||
class ProfileHealthTest(unittest.TestCase):
|
||||
"""One cell per graded behaviour; each names the mutant that kills it."""
|
||||
|
||||
def setUp(self):
|
||||
self._tmp = tempfile.TemporaryDirectory(prefix="q81cell-")
|
||||
self.base = Path(self._tmp.name)
|
||||
self.addCleanup(self._tmp.cleanup)
|
||||
|
||||
# ---- fixture -----------------------------------------------------------
|
||||
def make_home(self, name="home", *, dirs=DIRS, dirs_as_files=(), config=GOOD_CONFIG,
|
||||
config_bytes=None):
|
||||
home = self.base / name
|
||||
home.mkdir(parents=True, exist_ok=True)
|
||||
if config_bytes is not None:
|
||||
(home / "config.yaml").write_bytes(config_bytes)
|
||||
elif config is not None:
|
||||
(home / "config.yaml").write_text(config, encoding="utf-8")
|
||||
for d in dirs:
|
||||
if d in dirs_as_files:
|
||||
(home / d).write_text("", encoding="utf-8")
|
||||
else:
|
||||
(home / d).mkdir(exist_ok=True)
|
||||
return home
|
||||
|
||||
def run_tool(self, *args, env_extra=None, drop_hermes_home=True):
|
||||
env = dict(os.environ)
|
||||
env.pop("HERMES_PROFILES_DIR", None)
|
||||
if drop_hermes_home:
|
||||
env.pop("HERMES_HOME", None)
|
||||
env.update(env_extra or {})
|
||||
return subprocess.run(
|
||||
[sys.executable, str(TOOL), *args],
|
||||
cwd=str(self.base),
|
||||
env=env,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
# ---- cells -------------------------------------------------------------
|
||||
def test_healthy_profile_exits_0(self):
|
||||
"""Killed by M5 (an extra expected directory nobody has) and M3 (rc 2/1 swap)."""
|
||||
home = self.make_home()
|
||||
r = self.run_tool("--profile", str(home))
|
||||
self.assertEqual(r.returncode, 0, r.stdout + r.stderr)
|
||||
self.assertIn("Profile is healthy", r.stdout)
|
||||
self.assertNotIn("Issues", r.stdout)
|
||||
|
||||
def test_missing_directory_exits_1(self):
|
||||
"""Killed by M4 (the missing-directory branch suppressed)."""
|
||||
home = self.make_home(dirs=("skills", "plugins", "cron"))
|
||||
r = self.run_tool("--profile", str(home))
|
||||
self.assertEqual(r.returncode, 1, r.stdout + r.stderr)
|
||||
self.assertIn("memories/ missing", r.stdout)
|
||||
self.assertNotIn("Profile is healthy", r.stdout)
|
||||
|
||||
def test_absent_profile_dir_exits_2(self):
|
||||
"""Killed by M3 (absent home graded as a fault, rc 1, instead of ungradable)."""
|
||||
r = self.run_tool("--profile", str(self.base / "does-not-exist"))
|
||||
self.assertEqual(r.returncode, 2, r.stdout + r.stderr)
|
||||
self.assertIn("does not exist", r.stderr)
|
||||
self.assertEqual(r.stdout.strip(), "", "rc 2 must not print a verdict")
|
||||
|
||||
def test_skills_as_regular_file_exits_1(self):
|
||||
"""Killed by M1 (is_dir() weakened back to exists())."""
|
||||
home = self.make_home(dirs_as_files=("skills",))
|
||||
r = self.run_tool("--profile", str(home))
|
||||
self.assertEqual(r.returncode, 1, r.stdout + r.stderr)
|
||||
self.assertIn("skills exists but is not a directory", r.stdout)
|
||||
|
||||
def test_empty_config_exits_1(self):
|
||||
"""Killed by M2 (the empty-config grade removed)."""
|
||||
home = self.make_home(config="")
|
||||
r = self.run_tool("--profile", str(home))
|
||||
self.assertEqual(r.returncode, 1, r.stdout + r.stderr)
|
||||
self.assertIn("config.yaml is empty", r.stdout)
|
||||
|
||||
def test_invalid_yaml_exits_1(self):
|
||||
"""Killed by M2 (empty-only) and M6 (config graded by exists() alone)."""
|
||||
home = self.make_home(config="model: [unclosed\n - :\n\t:bad\n")
|
||||
r = self.run_tool("--profile", str(home))
|
||||
self.assertEqual(r.returncode, 1, r.stdout + r.stderr)
|
||||
self.assertIn("not valid YAML", r.stdout)
|
||||
|
||||
def test_config_not_a_mapping_exits_1(self):
|
||||
"""Killed by M6 (no parse, so a list config reads healthy)."""
|
||||
home = self.make_home(config="- just\n- a\n- list\n")
|
||||
r = self.run_tool("--profile", str(home))
|
||||
self.assertEqual(r.returncode, 1, r.stdout + r.stderr)
|
||||
self.assertIn("not a mapping", r.stdout)
|
||||
|
||||
def test_no_profile_names_nothing_exits_2(self):
|
||||
"""Killed by M7 (an implicit default home invented instead of refusing)."""
|
||||
r = self.run_tool()
|
||||
self.assertEqual(r.returncode, 2, r.stdout + r.stderr)
|
||||
self.assertIn("ungradable", r.stderr)
|
||||
# the refusal must name the missing input, not a missing directory: an invented
|
||||
# default home also exits 2 on this host, and that mutant must not read clean here.
|
||||
self.assertIn("no profile named", r.stderr)
|
||||
self.assertEqual(r.stdout.strip(), "", "rc 2 must not print a verdict")
|
||||
|
||||
def test_profile_name_resolves_under_root(self):
|
||||
"""Killed by M8 (a bare NAME taken as a relative path)."""
|
||||
root = self.base / "profiles"
|
||||
home = root / "volt"
|
||||
home.mkdir(parents=True)
|
||||
(home / "config.yaml").write_text(GOOD_CONFIG, encoding="utf-8")
|
||||
for d in DIRS:
|
||||
(home / d).mkdir()
|
||||
r = self.run_tool("--profile", "volt", "--profiles-root", str(root))
|
||||
self.assertEqual(r.returncode, 0, r.stdout + r.stderr)
|
||||
self.assertIn(str(home), r.stdout)
|
||||
# and HERMES_HOME alone, with no --profile, reaches the same home
|
||||
r2 = self.run_tool(env_extra={"HERMES_HOME": str(home)}, drop_hermes_home=False)
|
||||
self.assertEqual(r2.returncode, 0, r2.stdout + r2.stderr)
|
||||
self.assertIn(str(home), r2.stdout)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Reference in new issue
Block a user