test(issue-20): issue-15 leak checks judge only their own job ids and session

The onboarding tests compared whole listings of the repo's .mam, so a concurrent run's entries failed them. Session names are now unique per run; the check is that the sandbox's own job ids are absent from every real root (this checkout's and the recorded control plane's) and that no new entry there names the session. cli_defaults also checks that the audit log follows WORKSPACE_ROOT.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sdga4A8i1iSc8DaaW9iKU2
This commit is contained in:
GodopuandClaude Opus 5 committed 2026-09-15 02:02:52 +00:00
1 parent c5844a8e12
commit a2be70df1b
1 file changed
+59 -16
+59 -16
View File
@@ -16,12 +16,13 @@ import json
import os import os
import subprocess import subprocess
import sys import sys
import uuid
from pathlib import Path from pathlib import Path
import _mam_state_guard
REPO_ROOT = Path(__file__).resolve().parent.parent REPO_ROOT = Path(__file__).resolve().parent.parent
SKILLS = REPO_ROOT / ".agents" / "skills" SKILLS = REPO_ROOT / ".agents" / "skills"
REAL_JOBS = REPO_ROOT / ".mam" / "jobs"
REAL_LOGS = REPO_ROOT / ".mam" / "delegate_job_logs"
sys.path.insert(0, str(SKILLS)) sys.path.insert(0, str(SKILLS))
from lib_py.delegation import mqtt_common # noqa: E402 from lib_py.delegation import mqtt_common # noqa: E402
@@ -67,8 +68,10 @@ def test_logs_dir_follows_the_same_order(monkeypatch, tmp_path):
def test_cli_defaults_are_resolved_per_process(monkeypatch, tmp_path): def test_cli_defaults_are_resolved_per_process(monkeypatch, tmp_path):
"""registry.py / publish_event.py build their argparse defaults at call """registry.py / publish_event.py build their argparse defaults at call
time, so a process started with WORKSPACE_ROOT set registers there.""" time, so a process started with WORKSPACE_ROOT set registers there - and
seeds its audit log there too."""
monkeypatch.delenv("MAM_JOBS_DIR", raising=False) monkeypatch.delenv("MAM_JOBS_DIR", raising=False)
monkeypatch.delenv("DELEGATE_JOB_LOGS_DIR", raising=False)
env = dict(os.environ, WORKSPACE_ROOT=str(tmp_path), PYTHONPATH=f"{SKILLS}:{os.environ.get('PYTHONPATH', '')}") env = dict(os.environ, WORKSPACE_ROOT=str(tmp_path), PYTHONPATH=f"{SKILLS}:{os.environ.get('PYTHONPATH', '')}")
env.pop("MAM_JOBS_DIR", None) env.pop("MAM_JOBS_DIR", None)
res = subprocess.run( res = subprocess.run(
@@ -80,6 +83,7 @@ def test_cli_defaults_are_resolved_per_process(monkeypatch, tmp_path):
records = list((tmp_path / ".mam" / "jobs").glob("*.json")) records = list((tmp_path / ".mam" / "jobs").glob("*.json"))
assert len(records) == 1, records assert len(records) == 1, records
assert json.loads(records[0].read_text())["agent_session"] == "herdr:issue15-probe" assert json.loads(records[0].read_text())["agent_session"] == "herdr:issue15-probe"
assert (tmp_path / ".mam" / "delegate_job_logs" / records[0].stem).is_dir()
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -95,26 +99,65 @@ def _create_session_from_repo_root(sandbox: Path, session: str) -> subprocess.Co
) )
def _assert_registered_in_sandbox_only(sandbox: Path, session: str, before_jobs: set, before_logs: set, res): def _real_state_dirs(recorded: dict) -> list:
"""Every real registry and audit-log root this run could leak into: this
checkout's .mam and the control plane the ambient binding named (conftest
records it before dropping it)."""
jobs, logs = _mam_state_guard.state_dirs(_mam_state_guard.watch_roots(REPO_ROOT, recorded), recorded)
return jobs + logs
def _entries(dirs: list) -> set:
return {(d, name) for d in dirs for name in _listing(Path(d))}
def _unique(prefix: str) -> str:
"""A session name no concurrent run shares (Issue #20)."""
return f"{prefix}-{uuid.uuid4().hex[:8]}"
def _assert_registered_in_sandbox_only(sandbox: Path, session: str, real_dirs: list, before: set, res):
"""Judged on this test's own job ids and session only (Issue #20): live
delegations and other test runs may add entries to the real .mam
meanwhile, so comparing whole listings gave false failures."""
assert res.returncode == 0, res.stderr + res.stdout assert res.returncode == 0, res.stderr + res.stdout
assert _listing(REAL_JOBS) == before_jobs, "onboarding job leaked into the repo's .mam/jobs" records = {p.stem: json.loads(p.read_text()) for p in (sandbox / ".mam" / "jobs").glob("*.json")}
assert _listing(REAL_LOGS) == before_logs, "audit log leaked into the repo's .mam/delegate_job_logs" own = [jid for jid, r in records.items() if r.get("agent_session") == f"herdr:{session}"]
records = [json.loads(p.read_text()) for p in (sandbox / ".mam" / "jobs").glob("*.json")] assert own, records
assert any(r.get("agent_session") == f"herdr:{session}" for r in records), records for d in real_dirs:
for jid in own:
assert not (Path(d) / f"{jid}.json").exists(), f"onboarding job {jid} leaked into {d}"
assert not (Path(d) / jid).exists(), f"audit log {jid} leaked into {d}"
# A job that never reached the sandbox has an id we do not know: look for
# the session in whatever appeared in the real roots meanwhile.
for d, name in _entries(real_dirs) - before:
entry = Path(d) / name
meta = entry if name.endswith(".json") else entry / "meta.json"
try:
session_of = json.loads(meta.read_text()).get("agent_session")
except (OSError, ValueError):
continue
assert session_of != f"herdr:{session}", f"onboarding job for {session} leaked: {entry}"
def test_onboarding_job_stays_in_sandbox_with_explicit_env(mam_sandbox, mock_herdr, mock_agents): def test_onboarding_job_stays_in_sandbox_with_explicit_env(mam_sandbox, mock_herdr, mock_agents,
before_jobs, before_logs = _listing(REAL_JOBS), _listing(REAL_LOGS) _ambient_control_plane):
res = _create_session_from_repo_root(mam_sandbox, "issue15-explicit-creator-claude") session = _unique("issue15-explicit-creator-claude")
_assert_registered_in_sandbox_only(mam_sandbox, "issue15-explicit-creator-claude", before_jobs, before_logs, res) real_dirs = _real_state_dirs(_ambient_control_plane)
before = _entries(real_dirs)
res = _create_session_from_repo_root(mam_sandbox, session)
_assert_registered_in_sandbox_only(mam_sandbox, session, real_dirs, before, res)
def test_onboarding_job_follows_workspace_root_alone(mam_sandbox, mock_herdr, mock_agents, monkeypatch): def test_onboarding_job_follows_workspace_root_alone(mam_sandbox, mock_herdr, mock_agents, monkeypatch,
_ambient_control_plane):
"""Without the explicit MAM_JOBS_DIR / DELEGATE_JOB_LOGS_DIR overrides the """Without the explicit MAM_JOBS_DIR / DELEGATE_JOB_LOGS_DIR overrides the
WORKSPACE_ROOT that lib.sh exports must be enough to keep the record out WORKSPACE_ROOT that lib.sh exports must be enough to keep the record out
of the repo's registry.""" of the repo's registry."""
monkeypatch.delenv("MAM_JOBS_DIR", raising=False) monkeypatch.delenv("MAM_JOBS_DIR", raising=False)
monkeypatch.delenv("DELEGATE_JOB_LOGS_DIR", raising=False) monkeypatch.delenv("DELEGATE_JOB_LOGS_DIR", raising=False)
before_jobs, before_logs = _listing(REAL_JOBS), _listing(REAL_LOGS) session = _unique("issue15-wsroot-creator-claude")
res = _create_session_from_repo_root(mam_sandbox, "issue15-wsroot-creator-claude") real_dirs = _real_state_dirs(_ambient_control_plane)
_assert_registered_in_sandbox_only(mam_sandbox, "issue15-wsroot-creator-claude", before_jobs, before_logs, res) before = _entries(real_dirs)
res = _create_session_from_repo_root(mam_sandbox, session)
_assert_registered_in_sandbox_only(mam_sandbox, session, real_dirs, before, res)