"""Tests for task add-self-improvement-loop. Covers R1-R5 from tasks/add-self-improvement-loop/SPEC.md: install.sh and update.sh wiring, template validation, and loop creation from template. """ import json import subprocess import sys import importlib.util from pathlib import Path import pytest _FRAMEWORK = Path.home() / ".automaton" _INSTALL_SH = _FRAMEWORK / "scripts" / "install.sh" _UPDATE_SH = _FRAMEWORK / "scripts" / "update.sh" _STATUS_PY = _FRAMEWORK / "scripts" / "status.py" _TEMPLATE = _FRAMEWORK / "templates" / "loops" / "self-improvement" / "loop.json" _spec = importlib.util.spec_from_file_location("status_mod", _STATUS_PY) st = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(st) class TestInstallShWiring: def test_install_sh_creates_self_improvement_loop(self): content = _INSTALL_SH.read_text() assert "--create-loop self-improvement" in content assert "--from-template self-improvement" in content def test_install_sh_schedules_self_improvement_loop(self): content = _INSTALL_SH.read_text() assert "--install-schedule self-improvement" in content assert "--interval 3600" in content def test_install_sh_has_opt_out_message(self): content = _INSTALL_SH.read_text() assert "--pause-loop self-improvement" in content def test_install_sh_uses_framework_project(self): content = _INSTALL_SH.read_text() assert '--project "$FRAMEWORK_DIR"' in content def test_install_sh_non_fatal_on_failure(self): content = _INSTALL_SH.read_text() assert "|| true" in content class TestUpdateShWiring: def test_update_sh_bootstraps_self_improvement_loop(self): content = _UPDATE_SH.read_text() assert "--create-loop self-improvement" in content assert "--from-template self-improvement" in content def test_update_sh_has_idempotent_check(self): content = _UPDATE_SH.read_text() assert "if [ ! -d" in content assert "loops/self-improvement" in content def test_update_sh_schedules_loop(self): content = _UPDATE_SH.read_text() assert "--install-schedule self-improvement" in content def test_update_sh_non_fatal_on_failure(self): content = _UPDATE_SH.read_text() assert "|| true" in content class TestSelfImprovementTemplate: def test_template_has_audit_work_source(self): cfg = json.loads(_TEMPLATE.read_text()) assert cfg["work_source"]["kind"] == "audit" def test_template_has_correct_brakes(self): cfg = json.loads(_TEMPLATE.read_text()) assert cfg["brakes"]["max_iterations"] == 10 assert cfg["brakes"]["score_plateau_window"] == 3 def test_template_has_worktree_enabled(self): cfg = json.loads(_TEMPLATE.read_text()) assert cfg["blast_radius"]["use_worktree"] is True def test_template_has_file_scope(self): cfg = json.loads(_TEMPLATE.read_text()) scope = cfg["blast_radius"]["file_scope"] assert "scripts/" in scope assert "prompts/" in scope assert "tests/" in scope assert "design/" in scope def test_template_has_role_prompts(self): cfg = json.loads(_TEMPLATE.read_text()) roles = cfg["roles"] assert roles["implement"]["prompt"] == "loop-implement.md" assert roles["verify"]["prompt"] == "loop-verifier.md" assert roles["orchestrate"]["prompt"] == "loop-orchestrate.md" class TestCreateLoopFromTemplate: def test_create_loop_self_improvement(self, tmp_path): project = tmp_path / "fw" (project / ".automaton").mkdir(parents=True) class A: pass a = A() a.create_loop = "self-improvement" a.from_template = "self-improvement" a.project = str(project) rc = st.cmd_create_loop(a) assert rc == 0 loop_dir = project / ".automaton" / "loops" / "self-improvement" assert loop_dir.exists() assert (loop_dir / "loop.json").exists() assert (loop_dir / ".state.loop").exists() assert (loop_dir / ".state.log").exists() state = json.loads((loop_dir / ".state.loop").read_text()) assert state["status"] == "running" assert state["name"] == "self-improvement" cfg = json.loads((loop_dir / "loop.json").read_text()) assert cfg["name"] == "self-improvement" assert cfg["work_source"]["kind"] == "audit" def test_create_loop_idempotent_refuses_duplicate(self, tmp_path): project = tmp_path / "fw" (project / ".automaton").mkdir(parents=True) class A: pass a = A() a.create_loop = "self-improvement" a.from_template = "self-improvement" a.project = str(project) assert st.cmd_create_loop(a) == 0 rc = st.cmd_create_loop(a) assert rc == 2