test: cover stop contract, execution adapters, checkpointer race and runtime identity
Docker / build (push) Has been cancelled
Test / pytest (ubuntu-latest, 3.12) (push) Has been cancelled
Test / pytest (windows-latest, 3.11) (push) Has been cancelled
Test / pytest (windows-latest, 3.12) (push) Has been cancelled
Lint / ruff (push) Has been cancelled
Test / pytest (ubuntu-latest, 3.11) (push) Has been cancelled
Build / build (push) Has been cancelled

This commit is contained in:
m4
2026-09-13 15:12:17 +08:00
parent ea99ce9f7e
commit d4b53bfb08
37 changed files with 4889 additions and 11 deletions
+28
View File
@@ -0,0 +1,28 @@
"""Register every invocation before launching pytest, including startup errors."""
import json
import os
from pathlib import Path
import subprocess
import sys
root = Path(__file__).resolve().parents[3] / ".hermes/test-runtime/unified-execution/b04-control"
root.mkdir(parents=True, exist_ok=True)
nodes = sys.argv[2:]
for node in nodes:
path = root / (node + ".jsonl")
records = path.read_text().splitlines() if path.exists() else []
assert len(records) < 5, "node budget exhausted"
for node in nodes:
path = root / (node + ".jsonl")
used = len(path.read_text().splitlines()) if path.exists() else 0
with path.open("a") as out:
out.write(json.dumps(dict(node=node, attempt=used + 1, phase=sys.argv[1])) + "\n")
out.flush()
os.fsync(out.fileno())
result = subprocess.run([sys.executable, "-m", "pytest", "-q", *[
"tests/test_host_registry_control.py::test_" + node for node in nodes
]], capture_output=True, text=True)
print(result.stdout, end="")
print(result.stderr, end="", file=sys.stderr)
(root / (sys.argv[1] + "-" + "-".join(nodes) + ".txt")).write_text(result.stdout + result.stderr)
sys.exit(result.returncode)
+203
View File
@@ -0,0 +1,203 @@
"""Isolated B04 process-loss probe. Not a production owner or adapter."""
from __future__ import annotations
import asyncio
import dataclasses
import hashlib
import json
import os
from pathlib import Path
import pickle
import socket
import subprocess
import sys
import time
ROOT = Path(__file__).resolve().parents[3]
REPO = ROOT / "EvoScientist"
BASE = ROOT / ".hermes/test-runtime/unified-execution/b04"
TARGET = "b04_current_host_restart_identity_no_automatic_replay"
def append(path, value):
with path.open("a") as out:
out.write(json.dumps(value, sort_keys=True) + "\n")
out.flush()
os.fsync(out.fileno())
async def child(mode, directory):
started = time.perf_counter()
def blocked(*args, **kwargs):
raise AssertionError("B04 prohibits network")
socket.socket.connect = blocked
socket.socket.connect_ex = blocked
socket.getaddrinfo = blocked
sys.path.insert(0, str(REPO))
import importlib
from langchain_core.language_models.fake_chat_models import FakeMessagesListChatModel
from langchain_core.messages import AIMessage
from langgraph.checkpoint.memory import InMemorySaver
from EvoScientist.config.settings import EvoScientistConfig
from EvoScientist.llm.contracts import AgentInputV3, HmacGrantAuthority, WebHostContext
from EvoScientist.llm.model_config import FileEvoModelConfigStore
from EvoScientist.llm.runtime import EvoModelRuntime
from EvoScientist.llm.host_execution_registry import SQLiteHostRegistry
from EvoScientist.web_runtime import create_web_agent, web_tool_registry_manifest
from EvoScientist.workspace_files import ScopedFilesystemBackend
from tests.v3_fixtures import v3_payload, identity_ring, RUNTIME_SECRET, RUNTIME_KEY_ID
from tests.test_web_model_runtime import _preparation, _admission
import resource
imported = time.perf_counter()
module = importlib.import_module("EvoScientist.EvoScientist")
module._load_mcp_tools_cached = lambda **kw: {}
module._load_mcp_config_once = lambda: ("b04-empty", {})
entered = asyncio.Event()
class LocalBlockingModel(FakeMessagesListChatModel):
def bind_tools(self, tools, **kwargs):
return self
async def _agenerate(self, *args, **kwargs):
append(directory / "model-entries.jsonl", {"pid": os.getpid(), "mode": mode})
entered.set()
await asyncio.Event().wait()
class EvidenceSink:
async def commit(self, event):
append(directory / "events.jsonl", {
"event_id": event.event_id, "run_id": event.run_id,
"kind": event.kind, "payload": dict(event.payload),
})
return "committed"
async def confirm(self, *args):
raise AssertionError("unexpected commit ambiguity")
authority = HmacGrantAuthority(RUNTIME_SECRET, RUNTIME_KEY_ID)
store = FileEvoModelConfigStore(directory / "routes.yaml", admin_verifier=authority)
if mode == "start":
payload = v3_payload()
for provider in payload["providers"].values():
for model in provider["models"]:
model["context_window"] = 131072
store.bootstrap_for_development(payload)
config = EvoScientistConfig(enable_async_subagents=False, enable_scheduler=False,
memory_workers_enabled=False, auto_approve=False)
runtime = EvoModelRuntime(store, admission_verifier=authority, quote_authority=authority,
host_registry=SQLiteHostRegistry(directory / "host.sqlite", host_id="b04-host", boot_id=__import__("uuid").uuid4().hex),
identity_key_ring=identity_ring(),
model_factory=lambda **kw: LocalBlockingModel(responses=[AIMessage(content="unused")]),
agent_factory=lambda snapshot, host, models: create_web_agent(
snapshot=snapshot, host=host, model_set=models, config=config))
constructed = time.perf_counter()
metrics = {"mode": mode, "pid": os.getpid(), "runtime_instance_id": runtime.runtime_instance_id,
"import_seconds": imported-started, "runtime_setup_seconds": constructed-imported}
if mode == "start":
for name in ("files", "memory"):
(directory / name).mkdir(exist_ok=True)
tools, revision = web_tool_registry_manifest()
host = WebHostContext(str(directory / "files"), str(directory / "memory"),
ScopedFilesystemBackend(directory / "files"), InMemorySaver(),
tool_registry=tools, tool_registry_revision=revision,
tool_selector_threshold=10000, runtime_event_sink=EvidenceSink())
agent_input = AgentInputV3("B04 controlled host loss", "b04:isolated:thread")
t = time.perf_counter()
quote = await runtime.prepare_model_run(_preparation(authority, agent_input, title_policy="disabled"), agent_input, host)
metrics["prepare_seconds"] = time.perf_counter()-t
admission = _admission(authority, quote)
t = time.perf_counter()
run = await runtime.start_web_run(admission)
metrics["start_graph_seconds"] = time.perf_counter()-t
metrics["run_id"] = run.run_id
metrics["same_grant_same_object"] = await runtime.start_web_run(admission) is run
await asyncio.wait_for(entered.wait(), 10)
metrics["start_to_model_entry_seconds"] = time.perf_counter()-t
metrics["task_done_before_loss"] = run._agent_task.done()
with (directory / "admission.pickle").open("wb") as out:
pickle.dump(admission, out)
out.flush()
os.fsync(out.fileno())
else:
prior = json.loads((directory / "start.json").read_text())
metrics["previous_run_id"] = prior["run_id"]
metrics["incarnation_changed"] = prior["runtime_instance_id"] != runtime.runtime_instance_id
metrics["public_identity_query_methods"] = [name for name in ("inspect", "get_run", "check_run", "get_execution") if callable(getattr(runtime, name, None))]
metrics["prepared_count"] = len(runtime._prepared)
metrics["started_grants_count"] = len(runtime._started_grants)
# Trusted local test artifact, never an untrusted or production pickle.
with (directory / "admission.pickle").open("rb") as inp:
admission = pickle.load(inp)
try:
await runtime.start_web_run(admission)
except Exception as exc:
metrics["old_admission_result"] = str(exc)
else:
raise AssertionError("old admission unexpectedly started")
await asyncio.sleep(0.1)
metrics["model_entries_total"] = len((directory / "model-entries.jsonl").read_text().splitlines())
assert metrics["incarnation_changed"]
metrics["inspection"] = runtime.inspect(prior["run_id"])
assert metrics["old_admission_result"] == "EXECUTION_UNKNOWN"
assert metrics["inspection"]["execution_id"] == prior["run_id"]
assert metrics["inspection"]["status"] == "unknown"
assert metrics["inspection"]["resources_confirmed_exited"] is False
assert metrics["model_entries_total"] == 1
assert metrics["public_identity_query_methods"] == ["inspect"]
metrics["max_rss_bytes_macos"] = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
(directory / f"{mode}.json").write_text(json.dumps(metrics, indent=2))
print(json.dumps(metrics), flush=True)
if mode == "start":
# Deliberate abrupt loss while Graph is active: no cancellation/teardown.
os._exit(0)
def main():
if len(sys.argv) > 1:
asyncio.run(child(sys.argv[1], Path(sys.argv[2])))
print("B04 restart asyncio.run and interpreter exit", flush=True)
return
os.umask(0o077)
BASE.mkdir(parents=True, exist_ok=True)
ledger = BASE / "attempts.jsonl"
records = [json.loads(line) for line in ledger.read_text().splitlines()] if ledger.exists() else []
used = sum(r.get("phase") == "start" for r in records)
if used >= 5:
raise SystemExit("B04 cumulative budget exhausted")
number = used + 1
directory = BASE / f"attempt-{number}"
directory.mkdir()
home = directory / "home"
home.mkdir()
env = {"PATH": "/usr/bin:/bin", "HOME": str(home), "EVOSCIENTIST_HOME": str(home),
"EVOSCIENTIST_CONFIG_DIR": str(home / "config"), "PYTHON_DOTENV_DISABLED": "1",
"PYTEST_DISABLE_PLUGIN_AUTOLOAD": "1", "WEB_RUNTIME_TEST_KEY": "b04-local-dummy",
"PYTHONPATH": str(REPO), "LANG": "en_US.UTF-8"}
command = [str(REPO / ".venv/bin/python"), str(Path(__file__).resolve())]
snapshot = {name: hashlib.sha256((REPO / name).read_bytes()).hexdigest() for name in (
"EvoScientist/llm/runtime.py", "EvoScientist/llm/contracts.py", "EvoScientist/web_runtime.py",
"tests/support/b04_host_restart_probe.py")}
append(ledger, {"phase": "start", "target": TARGET, "attempt": number, "limit": 5,
"time": time.time(), "command": command, "snapshot_sha256": snapshot})
code = 0
for mode in ("start", "restart"):
t = time.perf_counter()
with (directory / f"{mode}.log").open("w") as out:
try:
result = subprocess.run(command + [mode, str(directory)], cwd=REPO, env=env,
stdout=out, stderr=subprocess.STDOUT, timeout=40)
code = result.returncode
except subprocess.TimeoutExpired:
code = 124
append(ledger, {"phase": "child_exit", "attempt": number, "mode": mode,
"exit_code": code, "wall_seconds": time.perf_counter()-t})
print((directory / f"{mode}.log").read_text())
if code:
break
append(ledger, {"phase": "result", "attempt": number, "exit_code": code,
"time": time.time(), "remaining": 5-number, "directory": str(directory)})
raise SystemExit(code)
if __name__ == "__main__":
main()
@@ -0,0 +1,41 @@
"""Isolated five-attempt budget for the new cross-Turn barrier target only."""
import json
import os
from pathlib import Path
import subprocess
import sys
repo = Path(__file__).resolve().parents[2]
root = repo.parent / ".hermes/test-runtime/unified-execution/b04-checkpoint-writer"
root.mkdir(parents=True, exist_ok=True)
node = "tests/test_checkpoint_writer_race.py::test_cross_turn_checkpoint_writer_barrier"
ledger = root / "attempts.jsonl"
records = [json.loads(line) for line in ledger.read_text().splitlines()] if ledger.exists() else []
attempt = 1 + sum(r.get("phase") == "start" for r in records)
assert attempt <= 5, "target budget exhausted"
home = root / f"home-{attempt}"
home.mkdir(mode=0o700)
env = {"HOME": str(home), "PATH": str(repo / ".venv/bin") + ":/usr/bin:/bin",
"PYTHONPATH": str(repo), "PYTHON_DOTENV_DISABLED": "1", "PYTEST_DISABLE_PLUGIN_AUTOLOAD": "1",
"PYTHONDONTWRITEBYTECODE": "1", "EVOSCIENTIST_HOME": str(home),
"EVOSCIENTIST_CONFIG_DIR": str(home / "config"), "XDG_CONFIG_HOME": str(home / "config"),
"EVOSCIENTIST_DATA_DIR": str(home / "data"), "EVOSCIENTIST_WORKSPACE_DIR": str(home / "workspace"),
"EVOSCIENTIST_SKILLS_DIR": str(home / "skills"), "EVOSCIENTIST_MEMORIES_DIR": str(home / "memory")}
command = [str(repo / ".venv/bin/python"), "-m", "pytest", "--noconftest", "-p", "no:cacheprovider",
"-q", "-s", "--tb=short", node]
with ledger.open("a") as out:
if attempt == 1:
out.write(json.dumps(dict(phase="registered", node=node, used=0, limit=5)) + "\n")
out.write(json.dumps(dict(phase="start", node=node, attempt=attempt, stage=sys.argv[1], command=command)) + "\n")
try:
result = subprocess.run(command, cwd=repo, env=env, capture_output=True, text=True, timeout=60)
except subprocess.TimeoutExpired as exc:
output = exc.stdout or b""
result = subprocess.CompletedProcess(command, 124, output.decode() if isinstance(output, bytes) else output, "timeout")
log = root / f"attempt-{attempt}.log"
log.write_text(result.stdout + result.stderr)
os.chmod(log, 0o600)
with ledger.open("a") as out:
out.write(json.dumps(dict(phase="result", node=node, attempt=attempt, exit_code=result.returncode, log=str(log))) + "\n")
print(result.stdout + result.stderr)
sys.exit(result.returncode)
@@ -0,0 +1,41 @@
"""Offline, bounded B04 continuation-only runner."""
import json
import os
from pathlib import Path
import subprocess
import sys
repo = Path(__file__).resolve().parents[2]
root = repo.parent / ".hermes/test-runtime/unified-execution/b04-continuation"
root.mkdir(parents=True, exist_ok=True)
node = "tests/test_continuation_authorization_contract.py::" + sys.argv[1]
ledger = root / "attempts.jsonl"
records = [json.loads(line) for line in ledger.read_text().splitlines()] if ledger.exists() else []
attempt = 1 + sum(r.get("phase") == "start" and r.get("node") == node for r in records)
assert attempt <= 5, "node budget exhausted"
home = root / f"home-{sys.argv[1]}-{attempt}"
home.mkdir(mode=0o700)
env = {"HOME": str(home), "PATH": str(repo / ".venv/bin") + ":/usr/bin:/bin",
"PYTHONPATH": str(repo), "PYTHON_DOTENV_DISABLED": "1", "PYTEST_DISABLE_PLUGIN_AUTOLOAD": "1",
"PYTHONDONTWRITEBYTECODE": "1", "EVOSCIENTIST_HOME": str(home),
"EVOSCIENTIST_CONFIG_DIR": str(home / "config"), "XDG_CONFIG_HOME": str(home / "config"),
"EVOSCIENTIST_DATA_DIR": str(home / "data"), "EVOSCIENTIST_WORKSPACE_DIR": str(home / "workspace"),
"EVOSCIENTIST_SKILLS_DIR": str(home / "skills"), "EVOSCIENTIST_MEMORIES_DIR": str(home / "memory")}
command = [str(repo / ".venv/bin/python"), "-m", "pytest", "--noconftest", "-p", "no:cacheprovider",
"-q", "-s", "--tb=short", "--disable-warnings", node]
with ledger.open("a") as out:
if attempt == 1:
out.write(json.dumps(dict(phase="registered", node=node, used=0, limit=5)) + "\n")
out.write(json.dumps(dict(phase="start", node=node, attempt=attempt, command=command)) + "\n")
try:
result = subprocess.run(command, cwd=repo, env=env, capture_output=True, text=True, timeout=60)
except subprocess.TimeoutExpired as exc:
output = exc.stdout or b""
result = subprocess.CompletedProcess(command, 124, output.decode() if isinstance(output, bytes) else output, "timeout")
log = root / f"{sys.argv[1]}-{attempt}.log"
log.write_text(result.stdout + result.stderr)
os.chmod(log, 0o600)
with ledger.open("a") as out:
out.write(json.dumps(dict(phase="result", node=node, attempt=attempt, exit_code=result.returncode, log=str(log))) + "\n")
print(result.stdout + result.stderr)
sys.exit(result.returncode)
+46
View File
@@ -0,0 +1,46 @@
"""Isolated B01 runner with durable per-attempt evidence, maximum three runs."""
import datetime
import json
import os
from pathlib import Path
import subprocess
import sys
repo = Path(__file__).resolve().parents[2]
root = repo.parent / ".hermes/test-runtime/unified-execution/b01"
root.mkdir(parents=True, exist_ok=True)
ledger = root / "attempts.jsonl"
attempts = ledger.read_text().splitlines() if ledger.exists() else []
if len(attempts) >= 3:
raise SystemExit("B01 budget exhausted")
attempt = len(attempts) + 1
home = root / f"attempt-{attempt}"
config = home / "config"
config.mkdir(parents=True, exist_ok=True)
(config / "settings.yaml").write_text("enable_async_subagents: false\nenable_scheduler: false\nmemory_workers_enabled: false\n")
env = {
"HOME": str(home), "PATH": str(repo / ".venv/bin") + ":/usr/bin:/bin",
"PYTHONPATH": str(repo), "PYTHON_DOTENV_DISABLED": "1",
"PYTEST_DISABLE_PLUGIN_AUTOLOAD": "1", "PYTHONDONTWRITEBYTECODE": "1",
"EVOSCIENTIST_HOME": str(home), "EVOSCIENTIST_CONFIG_DIR": str(config),
"XDG_CONFIG_HOME": str(config), "EVOSCIENTIST_DATA_DIR": str(home / "data"),
"EVOSCIENTIST_WORKSPACE_DIR": str(home / "workspace"),
"EVOSCIENTIST_SKILLS_DIR": str(home / "skills"),
"EVOSCIENTIST_MEMORIES_DIR": str(home / "memory"),
}
nodes = [
"test_explicit_web_factory_preserves_environment_and_globals",
"test_two_tenants_real_file_tools_and_sqlite_reopen",
"test_web_manual_execute_interrupts_before_backend",
]
command = [str(repo / ".venv/bin/python"), "-m", "pytest", "--noconftest", "-p", "no:cacheprovider", "-q", "--tb=short"]
command += ["tests/test_execution_adapter_embedding.py::" + n for n in nodes]
record = {"attempt": attempt, "started": datetime.datetime.now().isoformat(), "nodes": nodes, "command": command, "cwd": str(repo)}
with ledger.open("a") as handle:
handle.write(json.dumps(record) + "\n")
result = subprocess.run(command, cwd=repo, env=env, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
log = root / f"attempt-{attempt}.log"
log.write_text(result.stdout)
print(result.stdout)
print(json.dumps({"attempt": attempt, "exit_code": result.returncode, "log": str(log)}))
sys.exit(result.returncode)