Complete tasks 3-7: harden verdict parsing, outputs retention, base branch, linux schedule parity, claim loop task
CI / build (push) Has been cancelled
CI / build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user