Files
multi-agent-mux/tests/test_issue5_phase4_runtime.py
T
Godopu f413f6ada6 feat(loop): complete Issue #5 Phase 4 immutable runtime and freeze removal
- Implement eager module loading (lib_py.loop.eager) to preload all framework
  dependencies into sys.modules and enforce PYTHONDONTWRITEBYTECODE=1.
- Synchronize runtime protocol version with MAM_VERSION constant (4.3.0).
- Bypass /tmp/mam-loop-freeze.XXXXXX copy overhead by default in Python mode
  while preserving legacy rollback fallback (MAM_LOOP_PY=0 / MAM_LOOP_FREEZE=1).
- Add tests/test_issue5_phase4_runtime.py verifying eager import completeness,
  mid-flight code modification immunity (B-13), and freeze bypass.
- Pass full test suite (749 tests, 0 failures).
2026-09-07 12:59:45 +09:00

186 lines
6.6 KiB
Python

"""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
assert eager.FRAMEWORK_VERSION == "4.3.0"
eager.verify_framework_version("4.3.0")
# 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