"""Issue #5 Phase 4 — Immutable Runtime Verification & Freeze Removal. Verifies: - P4-01: Eager import completeness, bytecode inhibition (PYTHONDONTWRITEBYTECODE=1), and MAM_VERSION protocol sync. - P4-02: Mid-flight on-disk code modification immunity (B-13 bug prevention). - P4-03: Freeze bypass under Python mode (default) and legacy fallback preservation. """ from __future__ import annotations import glob import os import subprocess import sys import tempfile from pathlib import Path import pytest REPO_ROOT = Path(__file__).resolve().parent.parent SKILLS = REPO_ROOT / ".agents" / "skills" if str(SKILLS) not in sys.path: sys.path.insert(0, str(SKILLS)) from lib_py.loop import eager, parser, checkpoint, runner def test_p4_01_eager_import_completeness_and_bytecode_inhibition(monkeypatch): """P4-01: Verify all core framework modules are eagerly loaded and bytecode writes disabled.""" loaded = eager.eager_load() assert eager.is_eager_loaded() for mod in eager.CORE_MODULES: assert mod in sys.modules, f"Module {mod} was not eagerly loaded into sys.modules" # Verify bytecode inhibition assert sys.dont_write_bytecode is True assert os.environ.get("PYTHONDONTWRITEBYTECODE") == "1" # Verify framework version constant sync. The literal value is not pinned # here: tests/test_version_consistency.py owns the lockstep between # eager.FRAMEWORK_VERSION, lib.sh's MAM_VERSION, VERSIONS.md and the eight # SKILL.md files, so a release bump must not have to edit this file too. eager.verify_framework_version(eager.FRAMEWORK_VERSION) # Verify mismatch raises RuntimeError monkeypatch.setenv("MAM_VERSION", "9.9.9") with pytest.raises(RuntimeError, match="MAM_VERSION mismatch"): eager.verify_framework_version() def test_p4_01_loop_runner_instantiation_triggers_eager_load(): """P4-01: LoopRunner.__init__ must eagerly load all modules immediately.""" lr = runner.LoopRunner(["--creator", "test-agent", "--task", "test"]) assert eager.is_eager_loaded() assert lr.creator == "" # Not parsed until parse_args() def test_p4_02_midflight_code_replacement_stress(tmp_path): """P4-02: Simulates B-13 mid-flight disk corruption. A running Python loop process that has eagerly loaded its modules must continue executing correctly across iterations even if underlying source files on disk are overwritten with syntax-breaking garbage. """ # Create a sandbox directory with a copy of a worker module sandbox = tmp_path / "sandbox" sandbox.mkdir() mod_file = sandbox / "dummy_worker.py" mod_file.write_text( "def compute_verdict(val: int) -> str:\n" " return f'PASS (score={val})'\n", encoding="utf-8" ) runner_script = tmp_path / "run_subproc.py" script_content = ( "import sys, os\n" f"sys.path.insert(0, r'{SKILLS}')\n" f"sys.path.insert(0, r'{sandbox}')\n" "from lib_py.loop import eager, parser, checkpoint\n" "import dummy_worker\n" "eager.eager_load()\n" "print('READY', flush=True)\n" "line = sys.stdin.readline()\n" "# Invoke functions after disk file has been corrupted\n" "res1 = dummy_worker.compute_verdict(42)\n" "verdict = parser.parse_verdict('Review output\\nVERDICT: PASS')\n" "chk_path = sys.stdin.readline().strip()\n" "checkpoint.save_checkpoint(chk_path, {'status': 'OK', 'res': res1, 'verdict': verdict})\n" "loaded = checkpoint.load_checkpoint(chk_path)\n" "assert loaded['status'] == 'OK'\n" "print('FINISHED_SUCCESSFULLY', flush=True)\n" ) runner_script.write_text(script_content, encoding="utf-8") py_bin = sys.executable proc = subprocess.Popen( [py_bin, str(runner_script)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, ) # Wait for process to eagerly load and signal READY ready_line = proc.stdout.readline() assert ready_line.strip() == "READY", f"Child failed to start: {proc.stderr.read()}" # --- B-13 Corruption Phase --- # While process is suspended waiting on stdin, corrupt dummy_worker.py on disk mod_file.write_text("INVALID SYNTAX !!!\n unexpected EOF def broken():\n", encoding="utf-8") # Tell child process to proceed chk_target = tmp_path / "checkpoint.json" proc.stdin.write(f"PROCEED\n{chk_target}\n") proc.stdin.flush() out_line = proc.stdout.readline() assert out_line.strip() == "FINISHED_SUCCESSFULLY", f"Child error: {proc.stderr.read()}" proc.communicate(timeout=5) assert proc.returncode == 0 assert chk_target.exists() def test_p4_03_freeze_bypass_by_default(tmp_path): """P4-03: Under MAM_LOOP_PY=1 (default), run_loop.sh must bypass /tmp/mam-loop-freeze.*.""" run_loop_sh = SKILLS / "multi-agent-mux-loop" / "scripts" / "run_loop.sh" env = os.environ.copy() env.pop("MAM_LOOP_FREEZE_DIR", None) env.pop("MAM_LOOP_FREEZE", None) env.pop("MAM_LOOP_PY", None) # defaults to 1 # Snapshot current freeze dirs in /tmp before_dirs = set(glob.glob(f"{tempfile.gettempdir()}/mam-loop-freeze.*")) res = subprocess.run( ["bash", str(run_loop_sh), "--help"], capture_output=True, text=True, env=env, cwd=str(REPO_ROOT), ) assert res.returncode == 1 assert "Usage: " in res.stdout after_dirs = set(glob.glob(f"{tempfile.gettempdir()}/mam-loop-freeze.*")) new_dirs = after_dirs - before_dirs assert len(new_dirs) == 0, f"Freeze dir was unexpectedly created: {new_dirs}" def test_p4_03_explicit_freeze_fallback(tmp_path): """P4-03: Setting MAM_LOOP_FREEZE=1 or MAM_LOOP_PY=0 restores freeze snapshot logic.""" run_loop_sh = SKILLS / "multi-agent-mux-loop" / "scripts" / "run_loop.sh" # 1. Test MAM_LOOP_FREEZE=1 env_freeze = os.environ.copy() env_freeze["MAM_LOOP_FREEZE"] = "1" env_freeze.pop("MAM_LOOP_FREEZE_DIR", None) res = subprocess.run( ["bash", str(run_loop_sh), "--help"], capture_output=True, text=True, env=env_freeze, cwd=str(REPO_ROOT), ) assert res.returncode == 1 assert "Usage: " in res.stdout # 2. Test MAM_LOOP_NO_FREEZE=1 overrides MAM_LOOP_FREEZE=1 env_no_freeze = os.environ.copy() env_no_freeze["MAM_LOOP_FREEZE"] = "1" env_no_freeze["MAM_LOOP_NO_FREEZE"] = "1" env_no_freeze.pop("MAM_LOOP_FREEZE_DIR", None) before_dirs = set(glob.glob(f"{tempfile.gettempdir()}/mam-loop-freeze.*")) res = subprocess.run( ["bash", str(run_loop_sh), "--help"], capture_output=True, text=True, env=env_no_freeze, cwd=str(REPO_ROOT), ) assert res.returncode == 1 after_dirs = set(glob.glob(f"{tempfile.gettempdir()}/mam-loop-freeze.*")) assert len(after_dirs - before_dirs) == 0