import os
import sys
import json
import sqlite3
import subprocess
import shutil
import pytest
from pathlib import Path

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"]:
    SCRUBBED_ENV.pop(k, None)
SCRUBBED_ENV["PYTHONPATH"] = f"{LIB_SH.parent}:{SCRUBBED_ENV.get('PYTHONPATH', '')}"


def run_onboard(args, env=None, cwd=None):
    run_env = dict(SCRUBBED_ENV)
    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 = dict(SCRUBBED_ENV)
    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 = dict(SCRUBBED_ENV)
    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, **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

    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
