Files
multi-agent-mux/tests/test_orc_onboard.py
T
GodopuandClaude Opus 5.5 8b47cc76ee test(issue-17): every test that sources lib.sh does it under its own WORKSPACE_ROOT (review grok, codex)
d198dd5 fixed one helper; the same defect was in eleven more modules
(reviews grok and codex R1/R2): their shells inherited the process
environment, so each `source lib.sh` rewrote <WORKSPACE_ROOT>/.mam/shim/herdr
- the checkout's own when the variable is unset or names this checkout (which
pytest_configure keeps), another workspace's under --noconftest.

- conftest: own_workspace_root, an opt-in fixture setting WORKSPACE_ROOT to
  <tmp_path>/.mam-test-state/workspace. Not autouse: runner.py and
  mqtt_common read WORKSPACE_ROOT in-process, and some tests unset it on
  purpose. mam_sandbox and explicit envs run later and still win.
- pytestmark usefixtures("own_workspace_root") in test_version_consistency,
  test_b19_headless_reconcile_fixes, test_b8_send_keys_verification,
  test_issue6_fail_closed, test_loop_cli, test_issue5_phase3_loop,
  test_issue5_phase4_runtime, test_o3_scoped_guard, test_issue25_plan_reuse,
  test_orc_onboard (their shells inherit os.environ, many with no env at all).
- test_orc_onboard (R2): SCRUBBED_ENV is taken at import and no longer
  carries WORKSPACE_ROOT; every call builds _scrubbed_env(root) with the root
  of the call (ws / cwd / mam_sandbox, else this test's).
- test_workspace_scope (unittest) and test_issue21_worktree_prereqs._mutate
  pin the root they already create.

Tests (test_issue17_workspace_root_isolation.py): W1 copies the checkout and
runs one test of each of those modules there with WORKSPACE_ROOT naming the
copy - the copy gets no .mam; W2 imports test_orc_onboard under a sentinel
root, then calls it under another - the sentinel stays empty. At d198dd5 both
fail (the copy gets .mam/shim/herdr; the sentinel gets it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGpJXhSZasJLU38ksDghe
2026-10-09 00:22:54 +09:00

579 lines
25 KiB
Python

import os
import sys
import json
import sqlite3
import subprocess
import shutil
import pytest
from pathlib import Path
# Issue #17: shells started here inherit a WORKSPACE_ROOT of this test's own
# (lib.sh would otherwise rewrite the checkout's .mam/shim/herdr).
pytestmark = pytest.mark.usefixtures("own_workspace_root")
REPO_ROOT = Path(__file__).parent.parent
LIB_SH = REPO_ROOT / ".agents" / "skills" / "lib.sh"
ONBOARD_SH = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-orc-onboard" / "scripts" / "orc_onboard.sh"
RECONCILE_SH = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-monitor" / "scripts" / "reconcile.sh"
SCRUBBED_ENV = dict(os.environ)
for k in ["CLAUDE_CODE_SESSION_ID", "ANTIGRAVITY_CONVERSATION_ID", "HERMES_SESSION_ID", "MAM_ORCHESTRATOR_UUIDS",
"WORKSPACE_ROOT"]:
SCRUBBED_ENV.pop(k, None)
SCRUBBED_ENV["PYTHONPATH"] = f"{LIB_SH.parent}:{SCRUBBED_ENV.get('PYTHONPATH', '')}"
def _scrubbed_env(root=None) -> dict:
"""SCRUBBED_ENV (taken at import) with the WORKSPACE_ROOT of now: `root`,
else this test's (own_workspace_root / mam_sandbox) - never the one the
module was imported under (Issue #17: lib.sh rewrites <it>/.mam/shim/herdr)."""
return dict(SCRUBBED_ENV, WORKSPACE_ROOT=str(root or os.environ["WORKSPACE_ROOT"]))
def run_onboard(args, env=None, cwd=None):
run_env = _scrubbed_env(cwd)
if cwd:
run_env["AGENT_SESSIONS_YAML"] = f"{cwd}/.mam/agent-sessions.yaml"
run_env["YAML_PATH"] = f"{cwd}/.mam/agent-sessions.yaml"
run_env["HOME_DIR"] = cwd
if env:
run_env.update(env)
cmd = ["bash", str(ONBOARD_SH)] + list(args)
return subprocess.run(cmd, capture_output=True, text=True, env=run_env, cwd=cwd)
def run_find_uuid(ws, agent, target="", env=None):
run_env = _scrubbed_env(ws)
run_env["AGENT_SESSIONS_YAML"] = f"{ws}/.mam/agent-sessions.yaml"
run_env["YAML_PATH"] = f"{ws}/.mam/agent-sessions.yaml"
run_env["HOME_DIR"] = ws
run_env["CLAUDE_PROJECT_DIR"] = f"{ws}/.claude/projects"
if env:
run_env.update(env)
cmd = ["bash", "-c", f"source '{LIB_SH}' && find_workspace_uuid '{ws}' '{agent}' '{target}'"]
res = subprocess.run(cmd, capture_output=True, text=True, env=run_env)
return res.stdout.strip()
def run_verify_uuid(ws, agent, uuid, row=None, mode="discover", env=None):
run_env = _scrubbed_env(ws)
run_env["AGENT_SESSIONS_YAML"] = f"{ws}/.mam/agent-sessions.yaml"
run_env["YAML_PATH"] = f"{ws}/.mam/agent-sessions.yaml"
run_env["HOME_DIR"] = ws
run_env["CLAUDE_PROJECT_DIR"] = f"{ws}/.claude/projects"
if env:
run_env.update(env)
row_json = json.dumps(row) if row else "{}"
cmd = ["bash", "-c", f"source '{LIB_SH}' && verify_session_uuid '{ws}' '{agent}' '{uuid}' '{row_json}' '{mode}'"]
res = subprocess.run(cmd, capture_output=True, text=True, env=run_env)
return res.returncode == 0
def dump_state(mam_sandbox, state):
yaml_path = str(mam_sandbox / ".mam" / "agent-sessions.yaml")
env = {"AGENT_SESSIONS_YAML": yaml_path, "YAML_PATH": yaml_path, "HOME_DIR": str(mam_sandbox)}
state_str = json.dumps(state)
cmd = f"source '{LIB_SH}' && atomic_dump_yaml '{yaml_path}' <<'PYEOF'\nd.update({state_str})\nPYEOF"
subprocess.run(["bash", "-c", cmd], env={**_scrubbed_env(mam_sandbox), **env}, check=True)
return env
def make_claude_transcript(mam_sandbox, uuid, target_dir=None):
key = str(mam_sandbox.resolve()).replace("/", "-").replace("_", "-")
if target_dir:
c_dir = target_dir / "projects" / key
else:
c_dir = mam_sandbox / ".claude" / "projects" / key
c_dir.mkdir(parents=True, exist_ok=True)
t_file = c_dir / f"{uuid}.jsonl"
t_file.write_text(f'{{"sessionId": "{uuid}", "cwd": "{mam_sandbox}"}}\n')
return t_file
# O-1: find_workspace_uuid excludes orchestrator UUID in discover mode
def test_o1_find_workspace_uuid_excludes_orchestrator(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
make_claude_transcript(mam_sandbox, orc_uuid)
state = {
"orchestrator_uuids": [orc_uuid],
"herdr_sessions": []
}
env = dump_state(mam_sandbox, state)
found = run_find_uuid(str(mam_sandbox), "claude", env=env)
assert found != orc_uuid
# O-2: find_workspace_uuid preserves target row own ID even if in orchestrator_uuids
def test_o2_find_workspace_uuid_preserves_own_id(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
make_claude_transcript(mam_sandbox, orc_uuid)
state = {
"orchestrator_uuids": [orc_uuid],
"herdr_sessions": [{
"name": "my-orc-session",
"status": "running",
"claude_session_id_own": orc_uuid,
"pane": {"cwd": str(mam_sandbox)}
}]
}
env = dump_state(mam_sandbox, state)
found = run_find_uuid(str(mam_sandbox), "claude", target="my-orc-session", env=env)
assert found == orc_uuid
# O-3: Baseline non-orchestrator transcript is found
def test_o3_find_workspace_uuid_finds_normal_subagent(mam_sandbox):
sub_uuid = "02222222-2222-2222-2222-222222222222"
make_claude_transcript(mam_sandbox, sub_uuid)
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
found = run_find_uuid(str(mam_sandbox), "claude", env=env)
assert found == sub_uuid
# O-4: find_workspace_uuid without target excludes orchestrator_uuids
def test_o4_find_workspace_uuid_without_target_excludes_orc(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
make_claude_transcript(mam_sandbox, orc_uuid)
state = {"orchestrator_uuids": [orc_uuid], "herdr_sessions": []}
env = dump_state(mam_sandbox, state)
found = run_find_uuid(str(mam_sandbox), "claude", target="", env=env)
assert found == ""
# O-5: MAM_ORCHESTRATOR_UUIDS env var override
def test_o5_env_override_orchestrator_uuids(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
make_claude_transcript(mam_sandbox, orc_uuid)
env = {
"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"),
"HOME_DIR": str(mam_sandbox),
"MAM_ORCHESTRATOR_UUIDS": orc_uuid
}
found = run_find_uuid(str(mam_sandbox), "claude", env=env)
assert found == ""
# O-6: Empty MAM_ORCHESTRATOR_UUIDS disables gate
def test_o6_empty_env_override_disables_gate(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
make_claude_transcript(mam_sandbox, orc_uuid)
state = {"orchestrator_uuids": [orc_uuid], "herdr_sessions": []}
env = dump_state(mam_sandbox, state)
env["MAM_ORCHESTRATOR_UUIDS"] = ""
found = run_find_uuid(str(mam_sandbox), "claude", env=env)
assert found == orc_uuid
# O-7: JSON array format in MAM_ORCHESTRATOR_UUIDS
def test_o7_json_array_env_override(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
make_claude_transcript(mam_sandbox, orc_uuid)
env = {
"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"),
"HOME_DIR": str(mam_sandbox),
"MAM_ORCHESTRATOR_UUIDS": f'["{orc_uuid}"]'
}
found = run_find_uuid(str(mam_sandbox), "claude", env=env)
assert found == ""
# O-8: verify_session_uuid in revalidate mode permits orchestrator_uuids for own row
def test_o8_revalidate_mode_permits_orchestrator_uuid(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
make_claude_transcript(mam_sandbox, orc_uuid)
row = {
"name": "my-orc",
"claude_session_id_own": orc_uuid,
"pane": {"cwd": str(mam_sandbox)}
}
env = {
"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"),
"HOME_DIR": str(mam_sandbox),
"MAM_ORCHESTRATOR_UUIDS": orc_uuid
}
assert run_verify_uuid(str(mam_sandbox), "claude", orc_uuid, row=row, mode="revalidate", env=env)
# O-9: verify_session_uuid in discover mode blocks orchestrator_uuids for unowned row
def test_o9_discover_mode_blocks_orchestrator_uuid(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
make_claude_transcript(mam_sandbox, orc_uuid)
row = {
"name": "subagent-session",
"claude_session_id_own": None,
"pane": {"cwd": str(mam_sandbox)}
}
env = {
"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"),
"HOME_DIR": str(mam_sandbox),
"MAM_ORCHESTRATOR_UUIDS": orc_uuid
}
assert not run_verify_uuid(str(mam_sandbox), "claude", orc_uuid, row=row, mode="discover", env=env)
# O-10: Baseline revalidate mode passes for non-orchestrator
def test_o10_revalidate_normal_subagent(mam_sandbox):
sub_uuid = "02222222-2222-2222-2222-222222222222"
make_claude_transcript(mam_sandbox, sub_uuid)
row = {"name": "subagent", "claude_session_id_own": sub_uuid, "pane": {"cwd": str(mam_sandbox)}}
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
assert run_verify_uuid(str(mam_sandbox), "claude", sub_uuid, row=row, mode="revalidate", env=env)
# O-12: orc_onboard.sh --uuid explicitly adds UUID
def test_o12_onboard_add_uuid(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
res = run_onboard(["--uuid", orc_uuid], env=env, cwd=str(mam_sandbox))
assert res.returncode == 0
assert "Successfully added" in res.stdout or "Successfully" in res.stdout
# Verify list
res_list = run_onboard(["--list"], env=env, cwd=str(mam_sandbox))
assert orc_uuid in res_list.stdout
# O-13: orc_onboard.sh --remove removes UUID
def test_o13_onboard_remove_uuid(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
run_onboard(["--uuid", orc_uuid], env=env, cwd=str(mam_sandbox))
res = run_onboard(["--remove", orc_uuid], env=env, cwd=str(mam_sandbox))
assert res.returncode == 0
# Issue #11: "removeed" was the naive ${MODE}ed conjugation.
assert "Successfully removed orchestrator UUID" in res.stdout, res.stdout
res_list = run_onboard(["--list"], env=env, cwd=str(mam_sandbox))
assert orc_uuid not in res_list.stdout
# O-14: orc_onboard.sh --dry-run does not mutate state
def test_o14_onboard_dry_run(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
res = run_onboard(["--uuid", orc_uuid, "--dry-run"], env=env, cwd=str(mam_sandbox))
assert res.returncode == 0
assert "[dry-run]" in res.stdout
res_list = run_onboard(["--list"], env=env, cwd=str(mam_sandbox))
assert orc_uuid not in res_list.stdout
# O-15: orc_onboard.sh duplicate add is idempotent
def test_o15_onboard_duplicate_add(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
run_onboard(["--uuid", orc_uuid], env=env, cwd=str(mam_sandbox))
res = run_onboard(["--uuid", orc_uuid], env=env, cwd=str(mam_sandbox))
assert res.returncode == 0
res_list = run_onboard(["--list"], env=env, cwd=str(mam_sandbox))
assert res_list.stdout.count(orc_uuid) == 1
# O-16: orc_onboard.sh rejects invalid UUID format (exit 2)
def test_o16_onboard_invalid_uuid_rejected(mam_sandbox):
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
res = run_onboard(["--uuid", "not-a-valid-uuid"], env=env, cwd=str(mam_sandbox))
assert res.returncode == 2
# O-17: orc_onboard.sh rejects adding ID owned by a running session (exit 1)
def test_o17_onboard_conflict_running_session(mam_sandbox):
sub_uuid = "02222222-2222-2222-2222-222222222222"
state = {
"orchestrator_uuids": [],
"herdr_sessions": [{
"name": "active-subagent",
"status": "running",
"claude_session_id_own": sub_uuid,
"pane": {"cwd": str(mam_sandbox)}
}]
}
env = dump_state(mam_sandbox, state)
res = run_onboard(["--uuid", sub_uuid], env=env, cwd=str(mam_sandbox))
assert res.returncode == 1
# O-18: orc_onboard.sh autodetects via environment variable (CLAUDE_CODE_SESSION_ID)
def test_o18_autodetect_via_env(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
env = {
"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"),
"HOME_DIR": str(mam_sandbox),
"CLAUDE_CODE_SESSION_ID": orc_uuid
}
# Run inside subshell where command line matches claude
cmd = f"export CLAUDE_CODE_SESSION_ID='{orc_uuid}' && exec -a claude bash '{ONBOARD_SH}'"
res = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, env={**_scrubbed_env(), **env}, cwd=str(mam_sandbox))
assert res.returncode == 0
res_list = run_onboard(["--list"], env=env, cwd=str(mam_sandbox))
assert orc_uuid in res_list.stdout
# O-19: orc_onboard.sh exit 3 when autodetect fails
def test_o19_autodetect_failure_exits_3(mam_sandbox):
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox), "MAM_AUTODETECT_FORCE_FAIL": "1"}
res = run_onboard([], env=env, cwd=str(mam_sandbox))
assert res.returncode == 3
# O-20: _validate fails on malformed orchestrator_uuids (not a list)
def test_o20_validate_fails_on_non_list_orchestrator_uuids(mam_sandbox):
state = {"orchestrator_uuids": "not-a-list", "herdr_sessions": []}
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "YAML_PATH": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
state_str = json.dumps(state)
cmd = f"source '{LIB_SH}' && atomic_dump_yaml '{env['YAML_PATH']}' <<'PYEOF'\nd.update({state_str})\nPYEOF"
res = subprocess.run(["bash", "-c", cmd], env={**_scrubbed_env(), **env}, capture_output=True, text=True)
assert res.returncode != 0
assert "VALIDATE" in res.stderr or "VALIDATE" in res.stdout
# O-21: _validate fails on duplicate orchestrator_uuids
def test_o21_validate_fails_on_duplicate_orchestrator_uuids(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
state = {"orchestrator_uuids": [orc_uuid, orc_uuid], "herdr_sessions": []}
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "YAML_PATH": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
state_str = json.dumps(state)
cmd = f"source '{LIB_SH}' && atomic_dump_yaml '{env['YAML_PATH']}' <<'PYEOF'\nd.update({state_str})\nPYEOF"
res = subprocess.run(["bash", "-c", cmd], env={**_scrubbed_env(), **env}, capture_output=True, text=True)
assert res.returncode != 0
# O-22: _validate fails on empty string in orchestrator_uuids
def test_o22_validate_fails_on_empty_string_orchestrator_uuid(mam_sandbox):
state = {"orchestrator_uuids": [""], "herdr_sessions": []}
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "YAML_PATH": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
state_str = json.dumps(state)
cmd = f"source '{LIB_SH}' && atomic_dump_yaml '{env['YAML_PATH']}' <<'PYEOF'\nd.update({state_str})\nPYEOF"
res = subprocess.run(["bash", "-c", cmd], env={**_scrubbed_env(), **env}, capture_output=True, text=True)
assert res.returncode != 0
# O-23: get_all_sessions_status folds orchestrator_uuids into hash
def test_o23_status_hash_includes_orchestrator_uuids(mam_sandbox):
state1 = {"orchestrator_uuids": ["01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"], "herdr_sessions": []}
state2 = {"orchestrator_uuids": ["02222222-2222-2222-2222-222222222222"], "herdr_sessions": []}
yaml_path = str(mam_sandbox / ".mam" / "agent-sessions.yaml")
cmd = f"""source '{LIB_SH}' && atomic_dump_yaml '{yaml_path}' <<'PYEOF'
import json, sys
h1 = get_all_sessions_status({json.dumps(state1)})
h2 = get_all_sessions_status({json.dumps(state2)})
if h1 == h2:
sys.exit(1)
PYEOF
"""
res = subprocess.run(["bash", "-c", cmd], env={**_scrubbed_env(), "AGENT_SESSIONS_YAML": yaml_path, "YAML_PATH": yaml_path}, capture_output=True, text=True)
assert res.returncode == 0
# O-24: Substring matching prevented in verify_session_uuid
def test_o24_substring_matching_prevented(mam_sandbox):
full_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
sub_str = "01eae7cf"
make_claude_transcript(mam_sandbox, sub_str)
row = {"name": "subagent", "claude_session_id_own": None, "pane": {"cwd": str(mam_sandbox)}}
env = {
"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"),
"HOME_DIR": str(mam_sandbox),
"MAM_ORCHESTRATOR_UUIDS": full_uuid
}
# sub_str is not full_uuid -> discover mode should NOT block sub_str
assert run_verify_uuid(str(mam_sandbox), "claude", sub_str, row=row, mode="discover", env=env)
# O-25: agy agent family orchestrator exclusion
def test_o25_agy_orchestrator_exclusion(mam_sandbox):
orc_uuid = "72d2d251-5a06-486b-92e5-7e46a7a80d2e"
db_dir = mam_sandbox / ".gemini" / "antigravity-cli" / "conversations"
db_dir.mkdir(parents=True, exist_ok=True)
db_path = db_dir / f"{orc_uuid}.db"
conn = sqlite3.connect(db_path)
conn.execute("CREATE TABLE steps (id INT)")
conn.execute("INSERT INTO steps VALUES (1)")
conn.commit()
conn.close()
lc_path = mam_sandbox / ".gemini" / "antigravity-cli" / "cache" / "last_conversations.json"
lc_path.parent.mkdir(parents=True, exist_ok=True)
lc_path.write_text(json.dumps({str(mam_sandbox): orc_uuid}))
state = {"orchestrator_uuids": [orc_uuid], "herdr_sessions": []}
env = dump_state(mam_sandbox, state)
found = run_find_uuid(str(mam_sandbox), "agy", env=env)
assert found != orc_uuid
# O-26: hermes agent family orchestrator exclusion
def test_o26_hermes_orchestrator_exclusion(mam_sandbox):
orc_uuid = "03333333-3333-3333-3333-333333333333"
hdb_dir = mam_sandbox / ".hermes"
hdb_dir.mkdir(parents=True, exist_ok=True)
hdb_path = hdb_dir / "state.db"
conn = sqlite3.connect(hdb_path)
conn.execute("CREATE TABLE sessions (id TEXT, cwd TEXT, started_at TEXT)")
conn.execute("INSERT INTO sessions VALUES (?, ?, ?)", (orc_uuid, str(mam_sandbox), "2026-08-12T00:00:00Z"))
conn.commit()
conn.close()
state = {"orchestrator_uuids": [orc_uuid], "herdr_sessions": []}
env = dump_state(mam_sandbox, state)
row = {"name": "subagent", "hermes_conversation_id_own": None, "pane": {"cwd": str(mam_sandbox)}}
assert not run_verify_uuid(str(mam_sandbox), "hermes", orc_uuid, row=row, mode="discover", env=env)
# O-27: Ignore env variable belonging to a different agent family (Challenge fix)
def test_o27_ignore_different_family_env_variable(mam_sandbox):
# Under claude process ancestor, ANTIGRAVITY_CONVERSATION_ID should be ignored
env = {
"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"),
"HOME_DIR": str(mam_sandbox),
"ANTIGRAVITY_CONVERSATION_ID": "72d2d251-5a06-486b-92e5-7e46a7a80d2e"
}
cmd = f"export ANTIGRAVITY_CONVERSATION_ID='72d2d251-5a06-486b-92e5-7e46a7a80d2e' && exec -a claude bash '{ONBOARD_SH}'"
res = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, env={**_scrubbed_env(), **env}, cwd=str(mam_sandbox))
assert res.returncode == 3
# O-28: Use env variable when agent family matches
def test_o28_use_family_matched_env_variable(mam_sandbox):
orc_uuid = "72d2d251-5a06-486b-92e5-7e46a7a80d2e"
env = {
"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"),
"HOME_DIR": str(mam_sandbox),
"ANTIGRAVITY_CONVERSATION_ID": orc_uuid
}
cmd = f"export ANTIGRAVITY_CONVERSATION_ID='{orc_uuid}' && exec -a agy bash '{ONBOARD_SH}'"
res = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, env={**_scrubbed_env(), **env}, cwd=str(mam_sandbox))
assert res.returncode == 0
res_list = run_onboard(["--list"], env=env, cwd=str(mam_sandbox))
assert orc_uuid in res_list.stdout
# O-29: Fresh claude session detected via CLAUDE_CODE_SESSION_ID
def test_o29_fresh_claude_session_detection(mam_sandbox):
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
env = {
"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"),
"HOME_DIR": str(mam_sandbox),
"CLAUDE_CODE_SESSION_ID": orc_uuid
}
cmd = f"export CLAUDE_CODE_SESSION_ID='{orc_uuid}' && exec -a claude bash '{ONBOARD_SH}'"
res = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, env={**_scrubbed_env(), **env}, cwd=str(mam_sandbox))
assert res.returncode == 0
res_list = run_onboard(["--list"], env=env, cwd=str(mam_sandbox))
assert orc_uuid in res_list.stdout
# O-30: argv takes precedence over env variable
def test_o30_argv_precedes_env(mam_sandbox):
argv_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
env_uuid = "02222222-2222-2222-2222-222222222222"
env = {
"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"),
"HOME_DIR": str(mam_sandbox),
"CLAUDE_CODE_SESSION_ID": env_uuid
}
cmd = f"export CLAUDE_CODE_SESSION_ID='{env_uuid}' && exec -a claude bash '{ONBOARD_SH}' --uuid {argv_uuid}"
res = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, env={**_scrubbed_env(), **env}, cwd=str(mam_sandbox))
assert res.returncode == 0
res_list = run_onboard(["--list"], env=env, cwd=str(mam_sandbox))
assert argv_uuid in res_list.stdout
assert env_uuid not in res_list.stdout
# O-32: ID format strictness rejects invalid strings
def test_o32_id_format_strictness(mam_sandbox):
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
for bad in ["../../etc/passwd", "a b", "fajon", "1785635248957", "1785635248957_fajon"]:
res = run_onboard(["--uuid", bad], env=env, cwd=str(mam_sandbox))
assert res.returncode == 2
# O-33: No workspace cache fallback (last_conversations.json excluded)
def test_o33_no_workspace_cache_fallback(mam_sandbox):
lc_path = mam_sandbox / ".gemini" / "antigravity-cli" / "cache" / "last_conversations.json"
lc_path.parent.mkdir(parents=True, exist_ok=True)
cached_uuid = "0f84dbf7-5ddf-4619-a813-7e1ae35be009"
lc_path.write_text(json.dumps({str(mam_sandbox): cached_uuid}))
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox), "MAM_AUTODETECT_FORCE_FAIL": "1"}
res = run_onboard([], env=env, cwd=str(mam_sandbox))
assert res.returncode == 3
# O-34: deploy/remove.sh fallback_assets contains multi-agent-mux-orc-onboard
def test_o34_remove_sh_fallback_assets():
remove_sh = REPO_ROOT / "deploy" / "remove.sh"
content = remove_sh.read_text()
assert ".agents/skills/multi-agent-mux-orc-onboard" in content
# O-35: deploy/gitea-ci.yml contains shellcheck line for orc_onboard.sh
def test_o35_gitea_ci_shellcheck():
ci_file = REPO_ROOT / "deploy" / "gitea-ci.yml"
content = ci_file.read_text()
assert "shellcheck .agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh" in content
# O-36: bash syntax check clean on orc_onboard.sh
def test_o36_bash_syntax_clean():
res = subprocess.run(["bash", "-n", str(ONBOARD_SH)], capture_output=True)
assert res.returncode == 0, res.stderr
# O-37: SKILL.md file exists and has valid frontmatter
def test_o37_skill_md_valid():
skill_md = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-orc-onboard" / "SKILL.md"
assert skill_md.is_file()
content = skill_md.read_text()
assert "name: multi-agent-mux-orc-onboard" in content
# O-38: atomic_dump_yaml handles empty orchestrator_uuids initialization
def test_o38_atomic_dump_yaml_initialization(mam_sandbox):
env = {"AGENT_SESSIONS_YAML": str(mam_sandbox / ".mam" / "agent-sessions.yaml"), "HOME_DIR": str(mam_sandbox)}
orc_uuid = "01eae7cf-1db6-4395-ba48-5fb02f4b6b1f"
res = run_onboard(["--uuid", orc_uuid], env=env, cwd=str(mam_sandbox))
assert res.returncode == 0
yaml_path = mam_sandbox / ".mam" / "agent-sessions.yaml"
assert yaml_path.is_file()
assert orc_uuid in yaml_path.read_text()
# O-40: Malformed orchestrator_uuids logs warning to stderr and degrades gracefully
def test_o40_malformed_orchestrator_uuids_degrades_open(mam_sandbox):
sub_uuid = "02222222-2222-2222-2222-222222222222"
make_claude_transcript(mam_sandbox, sub_uuid)
yaml_path = mam_sandbox / ".mam" / "agent-sessions.yaml"
yaml_path.parent.mkdir(parents=True, exist_ok=True)
yaml_path.write_text("orchestrator_uuids: 12345\nherdr_sessions: []\n")
env = {"AGENT_SESSIONS_YAML": str(yaml_path), "HOME_DIR": str(mam_sandbox)}
found = run_find_uuid(str(mam_sandbox), "claude", env=env)
assert found == sub_uuid