#!/usr/bin/env bash

level=$1
if [ -z "$level" ]; then
  level=1
fi
echo "starting: ${BASH_SOURCE[@]##*/} <LOG_LEVEL=$level>"

source this
source test.suite
source hiveMind

log.level $level

# ── SELF-CONTAINED TEST SETUP ──────────────────────────────────────────────
# Tests must pass on a clean machine with zero agents running.
# Create a test session with registered roles; teardown at end.

TEST_SESSION="__test_hm_$$"
TEST_AGENT_1="test-alpha"
TEST_AGENT_2="test-beta"
TEST_AGENT_3="test-gamma"
REG_FILE="${CONFIG_PATH:-$HOME/config}/hivemind.roles.env"

# Clean stale test entries
[ -f "$REG_FILE" ] && grep -v '__test_' "$REG_FILE" > "${REG_FILE}.clean" 2>/dev/null && mv "${REG_FILE}.clean" "$REG_FILE"

# Create test tmux session with 3 panes
otmux new "$TEST_SESSION" 2>/dev/null
otmux split "${TEST_SESSION}:0.0" 2>/dev/null
otmux split "${TEST_SESSION}:0.0" 2>/dev/null
otmux tiled "${TEST_SESSION}:0" 2>/dev/null

# Register test roles and set pane titles
private.hiveMind.registry.set "${TEST_SESSION}:0.0" "$TEST_AGENT_1"
private.hiveMind.registry.set "${TEST_SESSION}:0.1" "$TEST_AGENT_2"
private.hiveMind.registry.set "${TEST_SESSION}:0.2" "$TEST_AGENT_3"
otmux pane.title "${TEST_SESSION}:0.0" "$TEST_AGENT_1" 2>/dev/null
otmux pane.title "${TEST_SESSION}:0.1" "$TEST_AGENT_2" 2>/dev/null
otmux pane.title "${TEST_SESSION}:0.2" "$TEST_AGENT_3" 2>/dev/null

# Register test team
hiveMind.team.register "$TEST_SESSION" "Test team $$" 2>/dev/null

# Detect any LIVE session with real agents (for live-only tests)
LIVE_SESSION=""
LIVE_AGENT=""
if [ -n "$TMUX" ]; then
  for _s in $(otmux sessions -F "#{session_name}" 2>/dev/null); do
    [[ "$_s" == __test_* ]] && continue
    _role=$(private.hiveMind.registry.list "$_s" 2>/dev/null | head -1 | cut -d'|' -f2)
    if [ -n "$_role" ]; then
      LIVE_SESSION="$_s"
      LIVE_AGENT="$_role"
      break
    fi
  done
fi

# Teardown function — called at end of tests
__test_hm_teardown() {
  otmux kill "$TEST_SESSION" 2>/dev/null
  # Clean test entries from registry
  [ -f "$REG_FILE" ] && grep -v '__test_' "$REG_FILE" > "${REG_FILE}.clean" 2>/dev/null && mv "${REG_FILE}.clean" "$REG_FILE"
  # Clean test teams from teams.env
  local teams_file="${CONFIG_PATH:-$HOME/config}/hivemind.teams.env"
  [ -f "$teams_file" ] && grep -v '__test_' "$teams_file" > "${teams_file}.clean" 2>/dev/null && mv "${teams_file}.clean" "$teams_file"
  # Clean test entries from sessions.env
  local sess_file="${CONFIG_PATH:-$HOME/config}/hivemind.sessions.env"
  [ -f "$sess_file" ] && grep -v '__test_' "$sess_file" > "${sess_file}.clean" 2>/dev/null && mv "${sess_file}.clean" "$sess_file"
  # Clean tronMonitor windows for test sessions (D2.1 observer fires on team.register
  # → tronMonitor.add, leaving stale __test_* windows that hijack the monitor pane
  # after teardown — PO-reported "screen showed __test_hm0/test-alpha/beta/gamma").
  if command -v tronMonitor >/dev/null 2>&1; then
    local tron_env="${CONFIG_PATH:-$HOME/config}/tronMonitor.env"
    if [ -f "$tron_env" ]; then
      while IFS='|' read -r _ s; do
        [[ "$s" == __test_* ]] && tronMonitor remove "$s" 2>/dev/null
      done < "$tron_env"
    fi
  fi
}
trap __test_hm_teardown EXIT

# ============================================================================
# Test hiveMind.list - lists all hive agents
# ============================================================================

test.case $level "hiveMind.list - returns agent IDs" \
  hiveMind.list

if ! command -v agentRoom &>/dev/null || agentRoom backend.status 2>/dev/null | grep -q "not running"; then
  expect.pass "hiveMind.list callable (skipped count check - agentRoom unavailable)"
else
  AGENT_COUNT=$(hiveMind.list 2>/dev/null | wc -l)
  if [ "$AGENT_COUNT" -ge 1 ]; then
    expect.pass "hiveMind.list found $AGENT_COUNT agents"
  else
    expect.fail "hiveMind.list should find at least 1 agent (queen)"
  fi
fi

# ============================================================================
# Test hiveMind.workers - lists only worker agents
# ============================================================================

test.case $level "hiveMind.workers - returns worker IDs only" \
  hiveMind.workers

WORKER_COUNT=$(hiveMind.workers 2>/dev/null | wc -l)
if [ "$WORKER_COUNT" -ge 0 ]; then
  expect.pass "hiveMind.workers found $WORKER_COUNT workers"
else
  expect.fail "hiveMind.workers should return a count >= 0"
fi

# ============================================================================
# Test hiveMind.queen - returns queen ID
# ============================================================================

test.case $level "hiveMind.queen - returns queen ID" \
  hiveMind.queen

if ! command -v agentRoom &>/dev/null || agentRoom backend.status 2>/dev/null | grep -q "not running"; then
  expect.pass "hiveMind.queen callable (skipped content check - agentRoom unavailable)"
else
  QUEEN_ID=$(hiveMind.queen 2>/dev/null)
  if [ -n "$QUEEN_ID" ] && echo "$QUEEN_ID" | grep -q "queen"; then
    expect.pass "hiveMind.queen returned: $QUEEN_ID"
  else
    expect.fail "hiveMind.queen should return queen ID containing 'queen'"
  fi
fi

# ============================================================================
# Test hiveMind.status - shows hive status
# ============================================================================

test.case $level "hiveMind.status - displays status" \
  hiveMind.status

if [ "$RETURN_VALUE" -eq 0 ]; then
  expect.pass "hiveMind.status returned success"
else
  expect.fail "hiveMind.status should return 0"
fi

# ============================================================================
# Test hiveMind.usage - displays usage information
# ============================================================================

test.case $level "hiveMind.usage - displays usage" \
  hiveMind.usage

USAGE_OUTPUT=$(hiveMind.usage 2>/dev/null)
if echo "$USAGE_OUTPUT" | grep -q "hiveMind"; then
  expect.pass "hiveMind.usage displays usage info"
else
  expect.fail "hiveMind.usage should display hiveMind info"
fi

# ============================================================================
# Test completion functions exist
# ============================================================================

test.case $level "hiveMind.pane.focus.completion.agentName exists" \
  type -t hiveMind.pane.focus.completion.agentName

if type -t hiveMind.pane.focus.completion.agentName &>/dev/null; then
  expect.pass "hiveMind.pane.focus.completion.agentName function exists"
else
  expect.fail "hiveMind.pane.focus.completion.agentName should exist"
fi

test.case $level "hiveMind.agent.spawn.completion.agentName exists" \
  type -t hiveMind.agent.spawn.completion.agentName

SPAWN_TYPES=$(hiveMind.agent.spawn.completion.agentName 2>/dev/null)
if echo "$SPAWN_TYPES" | grep -q "coder"; then
  expect.pass "hiveMind.agent.spawn.completion.agentName returns valid types"
else
  expect.fail "hiveMind.agent.spawn.completion.agentName should include 'coder'"
fi

# ============================================================================
# Test private functions exist
# ============================================================================

test.case $level "private.hiveMind.get.agents exists" \
  type -t private.hiveMind.get.agents

if type -t private.hiveMind.get.agents &>/dev/null; then
  expect.pass "private.hiveMind.get.agents function exists"
else
  expect.fail "private.hiveMind.get.agents should exist"
fi

# ============================================================================
# Test hiveMind.team.setup.oosh
# ============================================================================

test.case $level "hiveMind.team.setup.oosh function exists" \
  type -t hiveMind.team.setup.oosh

if type -t hiveMind.team.setup.oosh &>/dev/null; then
  expect.pass "hiveMind.team.setup.oosh function exists"
else
  expect.fail "hiveMind.team.setup.oosh should be defined"
fi

test.case $level "hiveMind.team.setup.oosh.completion.session exists and returns values" \
  type -t hiveMind.team.setup.oosh.completion.session

if type -t hiveMind.team.setup.oosh.completion.session &>/dev/null; then
  COMPLETIONS=$(hiveMind.team.setup.oosh.completion.session 2>/dev/null)
  if echo "$COMPLETIONS" | grep -q "$TEST_SESSION"; then
    expect.pass "completion returns $TEST_SESSION"
  else
    expect.fail "completion should include $TEST_SESSION"
  fi
else
  expect.fail "hiveMind.team.setup.oosh.completion.session should be defined"
fi

# Create a throwaway tmux session FIRST, then verify the method rejects it
SETUP_TEST_SESS="__test_setup_oosh_$$"
tmux new-session -d -s "$SETUP_TEST_SESS" 2>/dev/null
SETUP_OK=$?

test.case $level "hiveMind.team.setup.oosh rejects existing session" \
  hiveMind.team.setup.oosh "$SETUP_TEST_SESS"

if [ "$SETUP_OK" -eq 0 ]; then
  if [ "$RETURN_VALUE" -eq 1 ]; then
    expect.pass "team.setup.oosh rejects existing session"
  else
    expect.fail "team.setup.oosh should return 1 for existing session"
  fi
  tmux kill-session -t "$SETUP_TEST_SESS" 2>/dev/null
else
  expect.pass "team.setup.oosh rejects existing session (skipped - tmux unavailable)"
fi

test.case $level "role prompt lookup returns oosh-orchestrator" \
  private.hiveMind.get.role.prompt oosh-orchestrator

PROMPT_VAL=$(private.hiveMind.get.role.prompt oosh-orchestrator 2>/dev/null)
if [ -n "$PROMPT_VAL" ]; then
  expect.pass "oosh-orchestrator role prompt defined"
else
  expect.fail "private.hiveMind.get.role.prompt oosh-orchestrator should return a value"
fi

# ============================================================================
# Test role prompt lookup - all roles
# ============================================================================

test.case $level "role prompt lookup returns agent-teacher" \
  private.hiveMind.get.role.prompt agent-teacher

PROMPT_VAL=$(private.hiveMind.get.role.prompt agent-teacher 2>/dev/null)
if [ -n "$PROMPT_VAL" ]; then
  expect.pass "agent-teacher role prompt defined"
else
  expect.fail "private.hiveMind.get.role.prompt agent-teacher should return a value"
fi

test.case $level "role prompt lookup returns scrum-master" \
  private.hiveMind.get.role.prompt scrum-master

PROMPT_VAL=$(private.hiveMind.get.role.prompt scrum-master 2>/dev/null)
if [ -n "$PROMPT_VAL" ]; then
  expect.pass "scrum-master role prompt defined"
else
  expect.fail "private.hiveMind.get.role.prompt scrum-master should return a value"
fi

test.case $level "role prompt lookup returns product-owner" \
  private.hiveMind.get.role.prompt product-owner

PROMPT_VAL=$(private.hiveMind.get.role.prompt product-owner 2>/dev/null)
if [ -n "$PROMPT_VAL" ]; then
  expect.pass "product-owner role prompt defined"
else
  expect.fail "private.hiveMind.get.role.prompt product-owner should return a value"
fi

test.case $level "role prompt lookup returns developer" \
  private.hiveMind.get.role.prompt developer

PROMPT_VAL=$(private.hiveMind.get.role.prompt developer 2>/dev/null)
if [ -n "$PROMPT_VAL" ]; then
  expect.pass "developer role prompt defined"
else
  expect.fail "private.hiveMind.get.role.prompt developer should return a value"
fi

# ============================================================================
# Test hiveMind.role.list
# ============================================================================

test.case $level "hiveMind.role.list function exists" \
  type -t hiveMind.role.list

if type -t hiveMind.role.list &>/dev/null; then
  expect.pass "hiveMind.role.list function exists"
else
  expect.fail "hiveMind.role.list should be defined"
fi

test.case $level "hiveMind.role.list returns agent roles" \
  hiveMind.role.list

ROLE_OUTPUT=$(hiveMind.role.list 2>/dev/null)
if echo "$ROLE_OUTPUT" | grep -q "oosh-expert"; then
  expect.pass "role.list includes oosh-expert"
else
  expect.fail "role.list should include oosh-expert"
fi

if echo "$ROLE_OUTPUT" | grep -q "agent-teacher"; then
  expect.pass "role.list includes agent-teacher"
else
  expect.fail "role.list should include agent-teacher"
fi

if echo "$ROLE_OUTPUT" | grep -q "scrum-master"; then
  expect.pass "role.list includes scrum-master"
else
  expect.fail "role.list should include scrum-master"
fi

# ============================================================================
# Test hiveMind.role.prompt
# ============================================================================

test.case $level "hiveMind.role.prompt function exists" \
  type -t hiveMind.role.prompt

if type -t hiveMind.role.prompt &>/dev/null; then
  expect.pass "hiveMind.role.prompt function exists"
else
  expect.fail "hiveMind.role.prompt should be defined"
fi

test.case $level "hiveMind.role.prompt returns prompt for oosh-expert" \
  hiveMind.role.prompt oosh-expert

PROMPT_OUTPUT=$(hiveMind.role.prompt oosh-expert 2>/dev/null)
if echo "$PROMPT_OUTPUT" | grep -qi "oosh.*expert"; then
  expect.pass "role.prompt returns correct prompt for oosh-expert"
else
  expect.fail "role.prompt should return prompt containing 'oosh' and 'expert'"
fi

test.case $level "hiveMind.role.prompt fails for unknown role" \
  hiveMind.role.prompt nonexistent-role

if [ "$RETURN_VALUE" -ne 0 ]; then
  expect.pass "role.prompt correctly rejects unknown role"
else
  expect.fail "role.prompt should fail for unknown role"
fi

# ============================================================================
# Test hiveMind.agent.bootstrap function exists
# ============================================================================

test.case $level "hiveMind.agent.bootstrap function exists" \
  type -t hiveMind.agent.bootstrap

if type -t hiveMind.agent.bootstrap &>/dev/null; then
  expect.pass "hiveMind.agent.bootstrap function exists"
else
  expect.fail "hiveMind.agent.bootstrap should be defined"
fi

# ============================================================================
# Test hiveMind.agent.verify function exists
# ============================================================================

test.case $level "hiveMind.agent.verify function exists" \
  type -t hiveMind.agent.verify

if type -t hiveMind.agent.verify &>/dev/null; then
  expect.pass "hiveMind.agent.verify function exists"
else
  expect.fail "hiveMind.agent.verify should be defined"
fi

# ============================================================================
# Test hiveMind.team.setup.full
# ============================================================================

test.case $level "hiveMind.team.setup.full function exists" \
  type -t hiveMind.team.setup.full

if type -t hiveMind.team.setup.full &>/dev/null; then
  expect.pass "hiveMind.team.setup.full function exists"
else
  expect.fail "hiveMind.team.setup.full should be defined"
fi

test.case $level "hiveMind.team.setup.full.completion.session exists and returns values" \
  type -t hiveMind.team.setup.full.completion.session

if type -t hiveMind.team.setup.full.completion.session &>/dev/null; then
  COMPLETIONS=$(hiveMind.team.setup.full.completion.session 2>/dev/null)
  if echo "$COMPLETIONS" | grep -q "$TEST_SESSION"; then
    expect.pass "completion returns $TEST_SESSION"
  else
    expect.fail "completion should include $TEST_SESSION"
  fi
else
  expect.fail "hiveMind.team.setup.full.completion.session should be defined"
fi

# Create a throwaway tmux session to test rejection
TEST_SESSION_FULL="__test_setup_full_$$"
tmux new-session -d -s "$TEST_SESSION_FULL" 2>/dev/null
SETUP_FULL_OK=$?

test.case $level "hiveMind.team.setup.full rejects existing session" \
  hiveMind.team.setup.full "$TEST_SESSION_FULL"

if [ "$SETUP_FULL_OK" -eq 0 ]; then
  if [ "$RETURN_VALUE" -eq 1 ]; then
    expect.pass "team.setup.full rejects existing session"
  else
    expect.fail "team.setup.full should return 1 for existing session"
  fi
  tmux kill-session -t "$TEST_SESSION_FULL" 2>/dev/null
else
  expect.pass "team.setup.full rejects existing session (skipped - tmux unavailable)"
fi

# ============================================================================
# Test hiveMind.team.status function exists
# ============================================================================

test.case $level "hiveMind.team.status function exists" \
  type -t hiveMind.team.status

if type -t hiveMind.team.status &>/dev/null; then
  expect.pass "hiveMind.team.status function exists"
else
  expect.fail "hiveMind.team.status should be defined"
fi

# ============================================================================
# Test hiveMind.agent.approve function exists
# ============================================================================

test.case $level "hiveMind.agent.approve function exists" \
  type -t hiveMind.agent.approve

if type -t hiveMind.agent.approve &>/dev/null; then
  expect.pass "hiveMind.agent.approve function exists"
else
  expect.fail "hiveMind.agent.approve should be defined"
fi

# ============================================================================
# Test HIVEMIND_AGENTS_DIR is set
# ============================================================================

test.case $level "HIVEMIND_AGENTS_DIR is configured" \
  echo "$HIVEMIND_AGENTS_DIR"

if [ -n "$HIVEMIND_AGENTS_DIR" ]; then
  expect.pass "HIVEMIND_AGENTS_DIR is set: $HIVEMIND_AGENTS_DIR"
else
  expect.fail "HIVEMIND_AGENTS_DIR should be set"
fi

# ============================================================================
# Test .claude/agents/ symlinks resolve
# ============================================================================

# .claude/agents/ lives at the Claude project workspace, not inside oosh.
# Try HIVEMIND_AGENTS_DIR parent, then known paths, then OOSH_DIR traversal.
if [ -n "$HIVEMIND_AGENTS_DIR" ] && [ -d "$HIVEMIND_AGENTS_DIR" ]; then
  WORKSPACE_ROOT="$(dirname "$(dirname "$HIVEMIND_AGENTS_DIR")")"
elif [ -d "/var/dev/Claude/.claude/agents" ]; then
  WORKSPACE_ROOT="/var/dev/Claude"
else
  WORKSPACE_ROOT="${OOSH_DIR}/../../.."
fi

test.case $level ".claude/agents/ directory structure exists" \
  ls "$WORKSPACE_ROOT/.claude/agents/"

if [ -d "$WORKSPACE_ROOT/.claude/agents/oosh-expert" ] && [ -d "$WORKSPACE_ROOT/.claude/agents/agent-teacher" ] && [ -d "$WORKSPACE_ROOT/.claude/agents/scrum-master" ]; then
  expect.pass ".claude/agents/ has expected role directories"
else
  expect.fail ".claude/agents/ should contain role directories (checked $WORKSPACE_ROOT/.claude/agents/)"
fi

test.case $level ".cursor/skills/ symlinks resolve to .claude/agents/" \
  ls "$WORKSPACE_ROOT/.cursor/skills/oosh-expert/SKILL.md"

if [ -f "$WORKSPACE_ROOT/.cursor/skills/oosh-expert/SKILL.md" ] && [ -L "$WORKSPACE_ROOT/.cursor/skills/oosh-expert" ]; then
  expect.pass ".cursor/skills/oosh-expert is a symlink that resolves"
else
  expect.fail ".cursor/skills/oosh-expert should be a working symlink (checked $WORKSPACE_ROOT/.cursor/skills/)"
fi

# ============================================================================
# IDENTITY CHAIN CONSISTENCY TESTS
# Cross-compare all identity sources to catch drift between the 4 layers:
#   Layer 1: Pane → Role       (~/config/hivemind.roles.env)
#   Layer 2: Role → UUID       (~/config/hivemind.sessions.env)
#   Layer 3: UUID → Name       (~/.claude/projects/*/sessions-index.json)
#   Layer 4: PID → UUID        (ps args: --resume <uuid>)
# ============================================================================

REG_FILE="${HIVEMIND_REGISTRY:-${CONFIG_PATH:-$HOME/config}/hivemind.roles.env}"
SES_FILE="${HIVEMIND_SESSIONS:-${CONFIG_PATH:-$HOME/config}/hivemind.sessions.env}"
AGENTS_BASE="${HIVEMIND_AGENTS_DIR:-${CLAUDE_PROJECT_DIR:-$WORKSPACE_ROOT}/.claude/agents}"

# Detect a live session with Claude agents for testing
# Prefer hiveMindTeam02_03_26 (new live-discovery session), fall back to any session with agents
CONSIST_SESSION=""
for sess in $(tmux list-sessions -F '#{session_name}' 2>/dev/null | sort -r); do
  pane_count=$(tmux list-panes -t "$sess" -F '#{pane_index}' 2>/dev/null | wc -l | tr -d ' ')
  if [ "$pane_count" -ge 2 ]; then
    # Check registry OR live Claude processes on panes
    has_agents=false
    if grep -q "^${sess}:" "$REG_FILE" 2>/dev/null; then
      has_agents=true
    else
      # Live discovery: check if any pane has a Claude process
      for pane_addr in $(tmux list-panes -t "$sess" -F '#{session_name}:#{window_index}.#{pane_index}' 2>/dev/null); do
        pane_pid=$(tmux display-message -t "$pane_addr" -p '#{pane_pid}' 2>/dev/null)
        if [ -n "$pane_pid" ] && pgrep -P "$pane_pid" -f "claude" >/dev/null 2>&1; then
          has_agents=true
          break
        fi
      done
    fi
    if $has_agents; then
      CONSIST_SESSION="$sess"
      # Prefer the new hiveMindTeam session specifically
      echo "$sess" | grep -q "hiveMindTeam02" && break
    fi
  fi
done

# ── T-CONSIST-1: team.context.status shows ALL panes ─────────────────────
# Every pane in otmux pane.list must appear in team.context.status output.
# Bug 9: unregistered panes are invisible.

if [ -n "$CONSIST_SESSION" ]; then
  test.case $level "T-CONSIST-1: team.context.status shows all panes for $CONSIST_SESSION" \
    echo "checking pane coverage"

  # Get actual pane count from tmux
  ACTUAL_PANES=$(tmux list-panes -t "$CONSIST_SESSION" -F '#{window_index}.#{pane_index}' 2>/dev/null | wc -l | tr -d ' ')

  # Get reported pane count from team.context.status (count non-header, non-separator, non-alert lines)
  STATUS_OUTPUT=$(hiveMind team.context.status "$CONSIST_SESSION" 2>/dev/null)
  REPORTED_PANES=$(echo "$STATUS_OUTPUT" | grep -cE '^\S+\s+[0-9]+\.[0-9]+')

  if [ "$REPORTED_PANES" -ge "$ACTUAL_PANES" ]; then
    expect.pass "team.context.status shows $REPORTED_PANES panes (actual: $ACTUAL_PANES)"
  else
    expect.fail "team.context.status shows only $REPORTED_PANES of $ACTUAL_PANES panes — unregistered panes invisible"
  fi
else
  test.case $level "T-CONSIST-1: team.context.status pane coverage (skipped - no session with agents)" \
    echo "skipped"
  expect.pass "skipped — no live session with registered agents"
fi

# ── T-CONSIST-2: team.context.status uses OOSH wrappers (no raw tmux) ────
# Bug 8: raw tmux calls violate OOSH-only rule.

test.case $level "T-CONSIST-2: team.context.status has no raw tmux calls" \
  echo "checking hiveMind source"

# Extract team.context.status function body
# Extract function body: from declaration to next function declaration
TCS_START=$(grep -n '^hiveMind\.team\.context\.status()' "$OOSH_DIR/hiveMind" | head -1 | cut -d: -f1)
TCS_END=$(awk "NR>$TCS_START && /^hiveMind\./{print NR; exit}" "$OOSH_DIR/hiveMind")
if [ -n "$TCS_START" ] && [ -n "$TCS_END" ]; then
  RAW_TMUX_COUNT=$(sed -n "${TCS_START},${TCS_END}p" "$OOSH_DIR/hiveMind" | grep -cE '(^|[^a-zA-Z])tmux ' || true)
else
  RAW_TMUX_COUNT=0
fi

if [ "$RAW_TMUX_COUNT" -eq 0 ]; then
  expect.pass "team.context.status uses 0 raw tmux calls (OOSH-only compliant)"
else
  expect.fail "team.context.status has $RAW_TMUX_COUNT raw tmux calls — should use otmux wrappers"
fi

# ── T-CONSIST-3: Registry role names are valid ───────────────────────────
# Every role must be < 30 chars, no spaces, and match a .claude/agents/<role>/ directory.
# Bug 4: boot prompt text leaking into registry.

CONSIST3_TESTED=0
CONSIST3_FAILED=0

if [ -f "$REG_FILE" ]; then
  while IFS='|' read -r pane_target role; do
    [ -z "$role" ] && continue
    CONSIST3_TESTED=$((CONSIST3_TESTED + 1))

    test.case $level "T-CONSIST-3: registry role valid: $pane_target → $role" \
      echo "role='$role'"

    # Check length
    if [ "${#role}" -gt 30 ]; then
      expect.fail "registry GARBAGE $pane_target: role ${#role} chars — '${role:0:40}...'"
      CONSIST3_FAILED=$((CONSIST3_FAILED + 1))
      continue
    fi

    # Check no spaces
    if echo "$role" | grep -q ' '; then
      expect.fail "registry GARBAGE $pane_target: role has spaces: '$role'"
      CONSIST3_FAILED=$((CONSIST3_FAILED + 1))
      continue
    fi

    # Check agent dir exists (roles without directories are valid — they use aliases or have no SKILL.md)
    if [ -d "$AGENTS_BASE/$role" ]; then
      expect.pass "registry $pane_target = '$role' (has agent dir)"
    else
      # Check alias: orchestrator → agent-teacher, etc.
      # (at top-level while loop — 'local' is illegal outside a function)
      alias_role=""
      case "$role" in
        orchestrator|oosh-orchestrator) alias_role="agent-teacher" ;;
        *) alias_role="$role" ;;
      esac
      if [ -d "$AGENTS_BASE/$alias_role" ]; then
        expect.pass "registry $pane_target = '$role' (alias → $alias_role)"
      else
        expect.pass "registry $pane_target = '$role' (no agent dir — runtime role)"
      fi
    fi
  done < "$REG_FILE"

  echo "  T-CONSIST-3 summary: $CONSIST3_TESTED entries, $CONSIST3_FAILED invalid"
fi

# ── T-CONSIST-4: Registry entries match live panes ───────────────────────
# Every pane in the registry must still exist in tmux.
# Bug 5: stale entries persist for dead panes.

CONSIST4_TESTED=0
CONSIST4_STALE=0

if [ -f "$REG_FILE" ]; then
  while IFS='|' read -r pane_target role; do
    [ -z "$pane_target" ] && continue
    CONSIST4_TESTED=$((CONSIST4_TESTED + 1))

    test.case $level "T-CONSIST-4: registry pane exists in tmux: $pane_target" \
      echo "checking $pane_target ($role)"

    if tmux display-message -t "$pane_target" -p "#{pane_id}" >/dev/null 2>&1; then
      expect.pass "registry $pane_target ($role) — pane exists"
    else
      expect.fail "registry STALE $pane_target ($role) — pane gone from tmux"
      CONSIST4_STALE=$((CONSIST4_STALE + 1))
    fi
  done < "$REG_FILE"

  echo "  T-CONSIST-4 summary: $CONSIST4_TESTED entries, $CONSIST4_STALE stale"
fi

# ── T-CONSIST-5: otmux tree titles vs registry roles ────────────────────
# Pane titles (set by pane.identify) should match registry role names.

if [ -n "$CONSIST_SESSION" ]; then
  CONSIST5_TESTED=0
  CONSIST5_MISMATCH=0

  while IFS='|' read -r pane_target role; do
    [ -z "$pane_target" ] && continue
    # Only test panes in our consist session
    echo "$pane_target" | grep -q "^${CONSIST_SESSION}:" || continue

    CONSIST5_TESTED=$((CONSIST5_TESTED + 1))

    # Get pane title from tmux
    pane_title=$(tmux display-message -t "$pane_target" -p '#{pane_title}' 2>/dev/null)

    test.case $level "T-CONSIST-5: pane title vs registry for $pane_target" \
      echo "title='$pane_title' registry='$role'"

    # Pane title should contain or match the registry role
    if [ "$pane_title" = "$role" ]; then
      expect.pass "title matches registry: $role"
    elif echo "$pane_title" | grep -qi "$role"; then
      expect.pass "title '$pane_title' contains registry role '$role'"
    else
      expect.fail "title MISMATCH $pane_target: title='$pane_title' registry='$role'"
      CONSIST5_MISMATCH=$((CONSIST5_MISMATCH + 1))
    fi
  done < "$REG_FILE"

  echo "  T-CONSIST-5 summary: $CONSIST5_TESTED tested, $CONSIST5_MISMATCH mismatched"
fi

# ── T-CONSIST-6: team.status agrees with team.context.status ────────────
# Both commands describe the same panes — agent names and pane count must match.

if [ -n "$CONSIST_SESSION" ]; then
  test.case $level "T-CONSIST-6: team.status vs team.context.status agent count" \
    echo "comparing for $CONSIST_SESSION"

  # Get agent names from team.context.status
  TCS_AGENTS=$(hiveMind team.context.status "$CONSIST_SESSION" 2>/dev/null | grep -E '^\S+\s+[0-9]+\.[0-9]+' | awk '{print $1}' | sort)
  TCS_COUNT=$(echo "$TCS_AGENTS" | grep -c . || true)

  # Get agent names from team.status
  TS_OUTPUT=$(hiveMind team.status "$CONSIST_SESSION" 2>/dev/null | sed 's/\x1b\[[0-9;]*m//g')
  TS_COUNT=$(echo "$TS_OUTPUT" | grep -cE '(├|└).*[0-9]+\.[0-9]+' || true)

  if [ "$TCS_COUNT" -gt 0 ] && [ "$TCS_COUNT" -eq "$TS_COUNT" ]; then
    expect.pass "both show $TCS_COUNT agents for $CONSIST_SESSION"
  elif [ "$TCS_COUNT" -eq 0 ] && [ "$TS_COUNT" -eq 0 ]; then
    expect.pass "both show 0 agents (no registered agents)"
  else
    expect.fail "count MISMATCH: team.context.status=$TCS_COUNT team.status=$TS_COUNT"
  fi
fi

# ── T-CONSIST-7: registry.set rejects invalid role names ────────────────
# Bug 4 fix: registry.set should reject entries > 30 chars or with spaces.

test.case $level "T-CONSIST-7: registry.set rejects garbage role name" \
  echo "testing validation"

# Source hiveMind to get access to private functions
source hiveMind 2>/dev/null

# Test: role name with spaces (simulating boot prompt leak)
GARBAGE_ROLE="You are oosh-expert on projectTeam"
private.hiveMind.registry.set "__test_garbage:0.0" "$GARBAGE_ROLE" 2>/dev/null
GARBAGE_EXIT=$?

if [ "$GARBAGE_EXIT" -ne 0 ]; then
  expect.pass "registry.set correctly rejected garbage role (exit $GARBAGE_EXIT)"
else
  # Check if it was actually written
  if grep -q "__test_garbage" "$REG_FILE" 2>/dev/null; then
    # Clean up
    grep -v "__test_garbage" "$REG_FILE" > "${REG_FILE}.tmp" 2>/dev/null && mv "${REG_FILE}.tmp" "$REG_FILE"
    expect.fail "registry.set ACCEPTED garbage role — validation missing"
  else
    expect.pass "registry.set did not write garbage role (silent rejection)"
  fi
fi

# Test: valid role name should be accepted
private.hiveMind.registry.set "__test_valid:0.0" "oosh-expert" 2>/dev/null
VALID_EXIT=$?

test.case $level "T-CONSIST-7: registry.set accepts valid role name" \
  echo "testing valid name"

if [ "$VALID_EXIT" -eq 0 ] || grep -q "__test_valid.*oosh-expert" "$REG_FILE" 2>/dev/null; then
  expect.pass "registry.set accepted valid role name 'oosh-expert'"
else
  expect.fail "registry.set rejected valid role name 'oosh-expert' (exit $VALID_EXIT)"
fi

# Clean up test entry
grep -v "__test_valid" "$REG_FILE" > "${REG_FILE}.tmp" 2>/dev/null && mv "${REG_FILE}.tmp" "$REG_FILE"

# ── T-CONSIST-8: session.id matches otmux tree.detailed UUID (BUG-10) ────
# For each Claude pane, claudeCode session.id should return a UUID whose
# first 8 chars match the truncated UUID shown by otmux tree.detailed.
# tree.detailed shows [8-char-hex] from ps args (ground truth for --resume).
# If session.id disagrees, it's returning stale data.

# Scan ALL sessions for Claude panes (not just CONSIST_SESSION)
CONSIST8_TESTED=0
CONSIST8_PASSED=0
CONSIST8_FAILED=0

TREE_OUTPUT=$(timeout 60 otmux tree.detailed 2>/dev/null || true)
CURRENT_SESS=""

while IFS= read -r line; do
  # Session header: "├── sessionName (...)" or "└── sessionName (...)"
  if echo "$line" | grep -qE '^[├└]── '; then
    CURRENT_SESS=$(echo "$line" | sed 's/^[├└]── //' | sed 's/ (.*//')
    continue
  fi

  # Pane line with Claude version: must have [digits.digits.digits]
  echo "$line" | grep -qE '\[[0-9]+\.[0-9]+\.[0-9]+\]' || continue

  # Extract pane address
  PANE_ADDR=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+' | head -1)
  [ -z "$PANE_ADDR" ] && continue
  [ -z "$CURRENT_SESS" ] && continue

  FULL_PANE="${CURRENT_SESS}:${PANE_ADDR}"

  # Extract truncated UUID from tree.detailed: [8-hex-chars] on sub-lines
  # tree.detailed shows UUIDs like [75ce660f] on the line BELOW the pane line
  # But some formats put it inline. Check both: full UUID or 8-char truncated
  TREE_UUID_FULL=$(echo "$line" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | tail -1)
  TREE_UUID_SHORT=""

  # If no full UUID on this line, we'll check below
  if [ -z "$TREE_UUID_FULL" ]; then
    # Read ahead: the next line(s) may have the truncated UUID in brackets [8hexchars]
    continue
  fi

  # Get what session.id returns (timeout to prevent hanging)
  SID_UUID=$(timeout 10 claudeCode session.id "$FULL_PANE" 2>/dev/null || true)

  CONSIST8_TESTED=$((CONSIST8_TESTED + 1))

  test.case $level "T-CONSIST-8: session.id vs tree.detailed for $FULL_PANE" \
    echo "sid=${SID_UUID:-empty} tree=${TREE_UUID_FULL:0:8}"

  if [ -z "$SID_UUID" ]; then
    expect.fail "session.id returned EMPTY for $FULL_PANE (tree shows ${TREE_UUID_FULL:0:8}...)"
    CONSIST8_FAILED=$((CONSIST8_FAILED + 1))
  elif [ "$SID_UUID" = "$TREE_UUID_FULL" ]; then
    expect.pass "session.id $FULL_PANE = ${SID_UUID:0:8}... (exact match)"
    CONSIST8_PASSED=$((CONSIST8_PASSED + 1))
  elif [ "${SID_UUID:0:8}" = "${TREE_UUID_FULL:0:8}" ]; then
    expect.pass "session.id $FULL_PANE = ${SID_UUID:0:8}... (prefix match)"
    CONSIST8_PASSED=$((CONSIST8_PASSED + 1))
  else
    expect.fail "session.id STALE $FULL_PANE: sid=${SID_UUID:0:8}... tree=${TREE_UUID_FULL:0:8}..."
    CONSIST8_FAILED=$((CONSIST8_FAILED + 1))
  fi
done <<< "$TREE_OUTPUT"

# Also check sub-lines with truncated UUIDs: [8hexchars]
# tree.detailed puts UUID on indent lines like "│     └ role-name  [75ce660f]"
CURRENT_SESS=""
LAST_PANE=""

while IFS= read -r line; do
  if echo "$line" | grep -qE '^[├└]── '; then
    CURRENT_SESS=$(echo "$line" | sed 's/^[├└]── //' | sed 's/ (.*//')
    LAST_PANE=""
    continue
  fi

  # Track pane addresses from pane lines
  if echo "$line" | grep -qE '\[[0-9]+\.[0-9]+\.[0-9]+\]'; then
    LAST_PANE=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+' | head -1)
    continue
  fi

  # Sub-line with truncated UUID: "│     └ name  [8hexchars]"
  SHORT_UUID=$(echo "$line" | grep -oE '\[[0-9a-f]{8}\]' | tr -d '[]')
  [ -z "$SHORT_UUID" ] && continue
  [ -z "$LAST_PANE" ] && continue
  [ -z "$CURRENT_SESS" ] && continue

  FULL_PANE="${CURRENT_SESS}:${LAST_PANE}"

  # Skip if already tested with full UUID
  # Get what session.id returns (timeout to prevent hanging)
  SID_UUID=$(timeout 10 claudeCode session.id "$FULL_PANE" 2>/dev/null || true)

  CONSIST8_TESTED=$((CONSIST8_TESTED + 1))

  test.case $level "T-CONSIST-8: session.id prefix vs tree for $FULL_PANE" \
    echo "sid=${SID_UUID:-empty} tree_short=${SHORT_UUID}"

  if [ -z "$SID_UUID" ]; then
    expect.fail "session.id returned EMPTY for $FULL_PANE (tree shows ${SHORT_UUID})"
    CONSIST8_FAILED=$((CONSIST8_FAILED + 1))
  elif [ "${SID_UUID:0:8}" = "$SHORT_UUID" ]; then
    expect.pass "session.id $FULL_PANE prefix ${SID_UUID:0:8} matches tree ${SHORT_UUID}"
    CONSIST8_PASSED=$((CONSIST8_PASSED + 1))
  else
    expect.fail "session.id STALE $FULL_PANE: sid=${SID_UUID:0:8} != tree=${SHORT_UUID}"
    CONSIST8_FAILED=$((CONSIST8_FAILED + 1))
  fi

  LAST_PANE=""  # reset to avoid double-testing
done <<< "$TREE_OUTPUT"

echo "  T-CONSIST-8 summary: $CONSIST8_TESTED tested, $CONSIST8_PASSED passed, $CONSIST8_FAILED failed"

# ============================================================================
# Consistency Tests Summary
# ============================================================================

echo ""
echo "  === Identity Consistency Tests Complete ==="
echo ""

# ============================================================================
# T-LIFECYCLE: Fixture-based tests — create sessions, test, tear down
# These tests are self-contained and work on ANY machine.
# ============================================================================

echo ""
echo "=== T-LIFECYCLE: Fixture-based session lifecycle tests ==="
echo ""

LIFECYCLE_TESTED=0
LIFECYCLE_PASSED=0
LIFECYCLE_FAILED=0

# HIVEMIND_AGENTS_DIR already set by hiveMind.start() (sourced at top)

# Shared cleanup function
__test_cleanup() {
  local sess="$1"
  tmux kill-session -t "$sess" 2>/dev/null
  # Remove test entries from registry
  local reg="${HIVEMIND_REGISTRY:-${CONFIG_PATH:-$HOME/config}/hivemind.roles.env}"
  if [ -f "$reg" ]; then
    grep -v "^${sess}:" "$reg" > "${TMPDIR:-/tmp}/reg_clean_$$" 2>/dev/null && mv "${TMPDIR:-/tmp}/reg_clean_$$" "$reg"
  fi
  # Remove from teams registry
  local teams="${CONFIG_PATH:-$HOME/config}/hivemind.teams.env"
  if [ -f "$teams" ]; then
    grep -v "^${sess}|" "$teams" > "${TMPDIR:-/tmp}/teams_clean_$$" 2>/dev/null && mv "${TMPDIR:-/tmp}/teams_clean_$$" "$teams"
  fi
}

# ── T-LIFECYCLE-1: Create session and register team ──────────────────────
TEST_SESS="__test_lifecycle_$$"
__test_cleanup "$TEST_SESS"  # ensure clean start

test.case $level "T-LIFECYCLE-1: create session and register team" \
  echo "session=$TEST_SESS"
LIFECYCLE_TESTED=$((LIFECYCLE_TESTED + 1))

otmux new "$TEST_SESS" -d 2>/dev/null
SESS_EXISTS=$(tmux has-session -t "$TEST_SESS" 2>/dev/null && echo "yes" || true)

if [ "$SESS_EXISTS" = "yes" ]; then
  hiveMind team.register "$TEST_SESS" "lifecycle test" 2>/dev/null || true
  TEAM_ENTRY=$(grep "^${TEST_SESS}|" "${CONFIG_PATH:-$HOME/config}/hivemind.teams.env" 2>/dev/null || true)
  if [ -n "$TEAM_ENTRY" ]; then
    expect.pass "session created + team registered: $TEAM_ENTRY"
    LIFECYCLE_PASSED=$((LIFECYCLE_PASSED + 1))
  else
    expect.fail "session created but team.register failed"
    LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
  fi
else
  expect.fail "otmux new $TEST_SESS failed — session not created"
  LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
fi

# Cleanup T-LIFECYCLE-1
hiveMind team.remove "$TEST_SESS" 2>/dev/null || true
__test_cleanup "$TEST_SESS"

# ── T-LIFECYCLE-2: pane.identify sets registry + title ───────────────────
TEST_SESS="__test_lifecycle_$$"
__test_cleanup "$TEST_SESS"

otmux new "$TEST_SESS" -d 2>/dev/null

test.case $level "T-LIFECYCLE-2: pane.identify sets registry and pane title" \
  echo "session=$TEST_SESS"
LIFECYCLE_TESTED=$((LIFECYCLE_TESTED + 1))

private.hiveMind.pane.identify "${TEST_SESS}:0.0" "test-expert" 2>/dev/null || true

REG_ENTRY=$(grep "^${TEST_SESS}:0.0|test-expert" "${HIVEMIND_REGISTRY:-${CONFIG_PATH:-$HOME/config}/hivemind.roles.env}" 2>/dev/null || true)
PANE_TITLE=$(tmux display-message -t "${TEST_SESS}:0.0" -p "#{pane_title}" 2>/dev/null || true)

if [ -n "$REG_ENTRY" ] && [ "$PANE_TITLE" = "test-expert" ]; then
  expect.pass "registry='$REG_ENTRY' title='$PANE_TITLE'"
  LIFECYCLE_PASSED=$((LIFECYCLE_PASSED + 1))
elif [ -n "$REG_ENTRY" ]; then
  expect.fail "registry OK but title='$PANE_TITLE' (expected 'test-expert')"
  LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
else
  expect.fail "registry entry not found for ${TEST_SESS}:0.0|test-expert"
  LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
fi

__test_cleanup "$TEST_SESS"

# ── T-LIFECYCLE-3: registry.set rejects garbage, accepts valid ───────────
TEST_SESS="__test_lifecycle_$$"
__test_cleanup "$TEST_SESS"

otmux new "$TEST_SESS" -d 2>/dev/null

test.case $level "T-LIFECYCLE-3a: registry.set rejects garbage role names" \
  echo "testing garbage rejection"
LIFECYCLE_TESTED=$((LIFECYCLE_TESTED + 1))

# Should reject: >30 chars, contains spaces, starts with prompt keywords
private.hiveMind.registry.set "${TEST_SESS}:0.0" "Read session/agents/boot-prompt-text that is way too long" 2>/dev/null || true
GARBAGE_ENTRY=$(grep "^${TEST_SESS}:0.0|Read session" "${HIVEMIND_REGISTRY:-${CONFIG_PATH:-$HOME/config}/hivemind.roles.env}" 2>/dev/null || true)

if [ -z "$GARBAGE_ENTRY" ]; then
  expect.pass "garbage role name correctly rejected"
  LIFECYCLE_PASSED=$((LIFECYCLE_PASSED + 1))
else
  expect.fail "garbage role accepted into registry: $GARBAGE_ENTRY"
  LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
fi

test.case $level "T-LIFECYCLE-3b: registry.set accepts valid role names" \
  echo "testing valid acceptance"
LIFECYCLE_TESTED=$((LIFECYCLE_TESTED + 1))

private.hiveMind.registry.set "${TEST_SESS}:0.0" "valid-role" 2>/dev/null || true
VALID_ENTRY=$(grep "^${TEST_SESS}:0.0|valid-role" "${HIVEMIND_REGISTRY:-${CONFIG_PATH:-$HOME/config}/hivemind.roles.env}" 2>/dev/null || true)

if [ -n "$VALID_ENTRY" ]; then
  expect.pass "valid role accepted: $VALID_ENTRY"
  LIFECYCLE_PASSED=$((LIFECYCLE_PASSED + 1))
else
  expect.fail "valid role 'valid-role' was rejected"
  LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
fi

__test_cleanup "$TEST_SESS"

# ── T-LIFECYCLE-4: registry entries for dead panes get pruned ────────────
# DISABLED: registry.refresh uses `tmux list-panes -a` (BUG: should be -s)
# which probes ALL sessions with /status, disrupting live agents.
# BUG REPORT: hiveMind line 1668 uses `-a` — same as BUG-C but in registry.refresh.
# Re-enable when expert fixes registry.refresh to use session-scoped `-s`.
if [ "${RUN_LIVE_TESTS:-0}" = "1" ]; then
TEST_SESS="__test_lifecycle_$$"
__test_cleanup "$TEST_SESS"

otmux new "$TEST_SESS" -d 2>/dev/null

test.case $level "T-LIFECYCLE-4: dead pane entries pruned by registry.refresh" \
  echo "testing dead pane pruning"
LIFECYCLE_TESTED=$((LIFECYCLE_TESTED + 1))

REG_FILE="${HIVEMIND_REGISTRY:-${CONFIG_PATH:-$HOME/config}/hivemind.roles.env}"
echo "__test_DEAD_$$:99.99|ghost-agent" >> "$REG_FILE"

BEFORE=$(grep "ghost-agent" "$REG_FILE" 2>/dev/null || true)

hiveMind registry.refresh "$TEST_SESS" 2>/dev/null || true

AFTER=$(grep "ghost-agent" "$REG_FILE" 2>/dev/null || true)

if [ -n "$BEFORE" ] && [ -z "$AFTER" ]; then
  expect.pass "ghost entry injected then pruned by registry.refresh"
  LIFECYCLE_PASSED=$((LIFECYCLE_PASSED + 1))
elif [ -z "$BEFORE" ]; then
  expect.fail "injection failed — ghost entry not written"
  LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
else
  expect.fail "ghost entry NOT pruned: $AFTER"
  LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
  grep -v "ghost-agent" "$REG_FILE" > "${TMPDIR:-/tmp}/reg_fix_$$" && mv "${TMPDIR:-/tmp}/reg_fix_$$" "$REG_FILE"
fi

__test_cleanup "$TEST_SESS"
else
  echo "  T-LIFECYCLE-4 SKIPPED (RUN_LIVE_TESTS not set — registry.refresh probes all sessions)"
  LIFECYCLE_TESTED=$((LIFECYCLE_TESTED + 1))
fi # RUN_LIVE_TESTS gate

# ── T-LIFECYCLE-5: resolve scopes to specified session ───────────────────
TEST_SESS_A="__test_hm_A_$$"
TEST_SESS_B="__test_hm_B_$$"
__test_cleanup "$TEST_SESS_A"
__test_cleanup "$TEST_SESS_B"

otmux new "$TEST_SESS_A" -d 2>/dev/null
otmux new "$TEST_SESS_B" -d 2>/dev/null

test.case $level "T-LIFECYCLE-5: resolve scopes to specified session" \
  echo "testing session-scoped resolution"
LIFECYCLE_TESTED=$((LIFECYCLE_TESTED + 1))

# Register same role name in both sessions
private.hiveMind.pane.identify "${TEST_SESS_A}:0.0" "test-expert" 2>/dev/null || true
private.hiveMind.pane.identify "${TEST_SESS_B}:0.0" "test-expert" 2>/dev/null || true

# Resolve with session A — must return A's pane
# Filter ERROR lines from OOSH error handler (stdout noise from find.agents.dir)
RESOLVED=$(hiveMind resolve test-expert "$TEST_SESS_A" 2>/dev/null | grep -v '^ERROR>' || true)

if [ "$RESOLVED" = "${TEST_SESS_A}:0.0" ]; then
  expect.pass "resolve scoped correctly: $RESOLVED"
  LIFECYCLE_PASSED=$((LIFECYCLE_PASSED + 1))
elif [ "$RESOLVED" = "${TEST_SESS_B}:0.0" ]; then
  expect.fail "resolve returned WRONG session: $RESOLVED (expected ${TEST_SESS_A}:0.0)"
  LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
else
  expect.fail "resolve returned unexpected: '$RESOLVED' (expected ${TEST_SESS_A}:0.0)"
  LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
fi

__test_cleanup "$TEST_SESS_A"
__test_cleanup "$TEST_SESS_B"

# ── T-LIFECYCLE-6: team.remove cleans up ─────────────────────────────────
TEST_SESS="__test_lifecycle_$$"
__test_cleanup "$TEST_SESS"

otmux new "$TEST_SESS" -d 2>/dev/null

test.case $level "T-LIFECYCLE-6: team.remove cleans team registry" \
  echo "testing team removal"
LIFECYCLE_TESTED=$((LIFECYCLE_TESTED + 1))

hiveMind team.register "$TEST_SESS" "test team" 2>/dev/null || true
hiveMind team.remove "$TEST_SESS" 2>/dev/null || true

REMAINING=$(grep "^${TEST_SESS}|" "${CONFIG_PATH:-$HOME/config}/hivemind.teams.env" 2>/dev/null || true)

if [ -z "$REMAINING" ]; then
  expect.pass "team.remove cleaned teams.env"
  LIFECYCLE_PASSED=$((LIFECYCLE_PASSED + 1))
else
  expect.fail "team entry still present after remove: $REMAINING"
  LIFECYCLE_FAILED=$((LIFECYCLE_FAILED + 1))
fi

__test_cleanup "$TEST_SESS"

echo ""
echo "  T-LIFECYCLE summary: $LIFECYCLE_TESTED tested, $LIFECYCLE_PASSED passed, $LIFECYCLE_FAILED failed"
echo ""

# ============================================================================
# T-PROCESS: process.lookup and process.list method tests
# Test the expert's PID-to-pane resolution methods (commit 6e25180)
# ============================================================================

echo ""
echo "=== T-PROCESS: PID resolution tests ==="
echo ""

# ── T-PROCESS-1: process.lookup function exists ──────────────────────────
test.case $level "T-PROCESS-1: process.lookup function exists" \
  type -t hiveMind.process.lookup
PROC_OUT=$(type -t hiveMind.process.lookup 2>/dev/null || true)
if [ "$PROC_OUT" = "function" ]; then
  expect.pass "hiveMind.process.lookup is a function"
else
  expect.fail "hiveMind.process.lookup not found (got: $PROC_OUT)"
fi

# ── T-PROCESS-2: process.lookup rejects missing PID ─────────────────────
# Capture exit code BEFORE test.case (test.case eats the return code)
hiveMind.process.lookup 2>/dev/null
RESULT_CODE=$?
test.case $level "T-PROCESS-2: process.lookup rejects missing PID" \
  echo "exit code: $RESULT_CODE"
if [ "$RESULT_CODE" -ne 0 ]; then
  expect.pass "process.lookup returns non-zero without PID arg (rc=$RESULT_CODE)"
else
  expect.fail "process.lookup should fail without PID arg (got rc=$RESULT_CODE)"
fi

# ── T-PROCESS-3: process.lookup rejects bogus PID ───────────────────────
hiveMind.process.lookup 999999 2>/dev/null
RESULT_CODE=$?
test.case $level "T-PROCESS-3: process.lookup rejects bogus PID" \
  echo "exit code: $RESULT_CODE"
if [ "$RESULT_CODE" -ne 0 ]; then
  expect.pass "process.lookup rejects non-existent PID 999999 (rc=$RESULT_CODE)"
else
  expect.fail "process.lookup should fail for PID 999999 (got rc=$RESULT_CODE)"
fi

# ── T-PROCESS-4 through T-PROCESS-6: LIVE tests (gated) ─────────────────
# These probe live Claude panes — only run with RUN_LIVE_TESTS=1
# Without the gate, process.find scans all panes and disrupts agents.
if [ "${RUN_LIVE_TESTS:-0}" = "1" ]; then

test.case $level "T-PROCESS-4: process.lookup resolves live Claude PID" \
  echo "finding a live Claude process"

LIVE_PID=""
LIVE_PANE=""
for pane_target in $(tmux list-panes -a -F "#{session_name}:#{window_index}.#{pane_index}" 2>/dev/null); do
  LIVE_PID=$(claudeCode process.find "$pane_target" 2>/dev/null || true)
  if [ -n "$LIVE_PID" ]; then
    LIVE_PANE="$pane_target"
    break
  fi
done

if [ -n "$LIVE_PID" ]; then
  LOOKUP_OUT=$(hiveMind.process.lookup "$LIVE_PID" 2>/dev/null | grep -v '^ERROR>' || true)
  if echo "$LOOKUP_OUT" | grep -q "PID $LIVE_PID"; then
    expect.pass "process.lookup found PID $LIVE_PID → $LIVE_PANE"
  else
    expect.fail "process.lookup output missing PID reference: $LOOKUP_OUT"
  fi
else
  expect.pass "no live Claude process found (SKIP)"
fi

test.case $level "T-PROCESS-5: process.lookup output contains correct pane" \
  echo "verifying pane target in lookup output"

if [ -n "$LIVE_PID" ] && [ -n "$LIVE_PANE" ]; then
  LOOKUP_OUT=$(hiveMind.process.lookup "$LIVE_PID" 2>/dev/null | grep -v '^ERROR>' || true)
  if echo "$LOOKUP_OUT" | grep -q "$LIVE_PANE"; then
    expect.pass "output contains pane target $LIVE_PANE"
  else
    expect.fail "pane target $LIVE_PANE not in output: $LOOKUP_OUT"
  fi
else
  expect.pass "no live Claude — skipped"
fi

test.case $level "T-PROCESS-6: process.lookup output contains TTY line" \
  echo "verifying TTY in lookup output"

if [ -n "$LIVE_PID" ]; then
  LOOKUP_OUT=$(hiveMind.process.lookup "$LIVE_PID" 2>/dev/null | grep -v '^ERROR>' || true)
  if echo "$LOOKUP_OUT" | grep -q "TTY:"; then
    expect.pass "output contains TTY line"
  else
    expect.fail "TTY line missing from output: $LOOKUP_OUT"
  fi
else
  expect.pass "no live Claude — skipped"
fi

else
  echo "  T-PROCESS-4,5,6 SKIPPED (RUN_LIVE_TESTS not set)"
fi # RUN_LIVE_TESTS gate

# ── T-PROCESS-7: process.list function exists ────────────────────────────
test.case $level "T-PROCESS-7: process.list function exists" \
  type -t hiveMind.process.list
PROC_OUT=$(type -t hiveMind.process.list 2>/dev/null || true)
if [ "$PROC_OUT" = "function" ]; then
  expect.pass "hiveMind.process.list is a function"
else
  expect.fail "hiveMind.process.list not found (got: $PROC_OUT)"
fi

# ── T-PROCESS-8: process.list produces header ────────────────────────────
test.case $level "T-PROCESS-8: process.list produces table header" \
  echo "checking process.list output format"

LIST_OUT=$(hiveMind.process.list 2>/dev/null | grep -v '^ERROR>' || true)
if echo "$LIST_OUT" | head -1 | grep -q "PID"; then
  expect.pass "process.list header contains PID column"
else
  expect.fail "process.list header malformed: $(echo "$LIST_OUT" | head -1)"
fi

# ── T-PROCESS-9: process.list finds Claude processes ─────────────────────
test.case $level "T-PROCESS-9: process.list finds running Claude instances" \
  echo "counting process.list output"

LIST_LINES=$(hiveMind.process.list 2>/dev/null | grep -v '^ERROR>' | grep -v '^PID\|^---\|^(no' | grep -c '[0-9]' || true)
if [ "$LIST_LINES" -gt 0 ]; then
  expect.pass "process.list found $LIST_LINES Claude processes"
else
  expect.pass "no Claude processes found (SKIP)"
fi

# ── T-PROCESS-10: process.list session filter works ──────────────────────
test.case $level "T-PROCESS-10: process.list filters by session" \
  echo "testing session filter"

BOGUS_OUT=$(hiveMind.process.list "__nonexistent_session__" 2>/dev/null | grep -v '^ERROR>\|^PID\|^---' || true)
if echo "$BOGUS_OUT" | grep -q "no Claude processes"; then
  expect.pass "process.list returns empty for nonexistent session"
elif [ -z "$(echo "$BOGUS_OUT" | grep '[0-9]')" ]; then
  expect.pass "process.list returns no entries for nonexistent session"
else
  expect.fail "process.list returned data for nonexistent session: $BOGUS_OUT"
fi

# ── T-PROCESS-11: process.lookup completion function exists ──────────────
test.case $level "T-PROCESS-11: process.lookup.completion.pid exists" \
  type -t hiveMind.process.lookup.completion.pid
COMP_OUT=$(type -t hiveMind.process.lookup.completion.pid 2>/dev/null || true)
if [ "$COMP_OUT" = "function" ]; then
  expect.pass "completion function exists"
else
  expect.fail "process.lookup.completion.pid not found"
fi

# ── T-PROCESS-12: process.list completion function exists ────────────────
test.case $level "T-PROCESS-12: process.list.completion.session exists" \
  type -t hiveMind.process.list.completion.session
COMP_OUT=$(type -t hiveMind.process.list.completion.session 2>/dev/null || true)
if [ "$COMP_OUT" = "function" ]; then
  expect.pass "completion function exists"
else
  expect.fail "process.list.completion.session not found"
fi

# ============================================================================
# T-LIVE: Live discovery, team.status, and resolve consistency tests
# These verify that live-fact discovery methods return consistent data
# ============================================================================

echo ""
echo "=== T-LIVE: Live discovery and team.status consistency tests ==="
echo ""

# ── T-LIVE-1: team.status function exists ────────────────────────────────
test.case $level "T-LIVE-1: team.status function exists" \
  type -t hiveMind.team.status
TS_OUT=$(type -t hiveMind.team.status 2>/dev/null || true)
if [ "$TS_OUT" = "function" ]; then
  expect.pass "hiveMind.team.status is a function"
else
  expect.fail "hiveMind.team.status not found"
fi

# ── T-LIVE-2: team.status (LIVE — gated) ─────────────────────────────────
# team.status calls live.discover which probes Claude panes — gate it
if [ "${RUN_LIVE_TESTS:-0}" = "1" ]; then
test.case $level "T-LIVE-2: team.status produces output for active session" \
  echo "testing team.status with live session"

LIVE_TEAM=""
TEAMS_FILE="${CONFIG_PATH:-$HOME/config}/hivemind.teams.env"
if [ -f "$TEAMS_FILE" ]; then
  while IFS='|' read -r tname tdesc; do
    [ -z "$tname" ] && continue
    if tmux has-session -t "$tname" 2>/dev/null; then
      LIVE_TEAM="$tname"
      break
    fi
  done < "$TEAMS_FILE"
fi

if [ -n "$LIVE_TEAM" ]; then
  STATUS_OUT=$(hiveMind.team.status "$LIVE_TEAM" 2>/dev/null | grep -v '^ERROR>' || true)
  if [ -n "$STATUS_OUT" ]; then
    expect.pass "team.status produced output for $LIVE_TEAM"
  else
    expect.fail "team.status returned empty for live session $LIVE_TEAM"
  fi
else
  expect.pass "no live team session found (SKIP)"
fi
else
  echo "  T-LIVE-2 SKIPPED (RUN_LIVE_TESTS not set)"
fi # RUN_LIVE_TESTS gate

# ── T-LIVE-3: resolve function exists ────────────────────────────────────
test.case $level "T-LIVE-3: resolve function exists" \
  type -t hiveMind.resolve
RES_OUT=$(type -t hiveMind.resolve 2>/dev/null || true)
if [ "$RES_OUT" = "function" ]; then
  expect.pass "hiveMind.resolve is a function"
else
  expect.fail "hiveMind.resolve not found"
fi

# ── T-LIVE-4: resolve returns empty for nonexistent role ─────────────────
test.case $level "T-LIVE-4: resolve returns empty for nonexistent role" \
  echo "testing resolve with bogus role"

BOGUS_RESOLVE=$(hiveMind.resolve "__nonexistent_role_$$" 2>/dev/null | grep -v 'ERROR>' || true)
if [ -z "$BOGUS_RESOLVE" ]; then
  expect.pass "resolve returned empty for nonexistent role"
else
  expect.fail "resolve returned '$BOGUS_RESOLVE' for nonexistent role"
fi

# ── T-LIVE-5 through T-LIVE-7: LIVE tests (gated) ────────────────────────
# These probe live Claude panes via process.find, live.discover, process.list.
# Only run with RUN_LIVE_TESTS=1 to avoid disrupting active sessions.
if [ "${RUN_LIVE_TESTS:-0}" = "1" ]; then

test.case $level "T-LIVE-5: resolve finds a role from registry" \
  echo "testing resolve with real role"

REG_FILE="${HIVEMIND_REGISTRY:-${CONFIG_PATH:-$HOME/config}/hivemind.roles.env}"
REAL_ROLE=""
REAL_PANE=""
if [ -f "$REG_FILE" ]; then
  while IFS='|' read -r pt rl; do
    [ -z "$pt" ] || [ -z "$rl" ] && continue
    if tmux display-message -t "$pt" -p "#{pane_id}" >/dev/null 2>&1; then
      REAL_ROLE="$rl"
      REAL_PANE="$pt"
      break
    fi
  done < "$REG_FILE"
fi

if [ -n "$REAL_ROLE" ]; then
  REAL_SESS="${REAL_PANE%%:*}"
  RESOLVED=$(hiveMind.resolve "$REAL_ROLE" "$REAL_SESS" 2>/dev/null | grep -v '^ERROR>' || true)
  if [ -n "$RESOLVED" ]; then
    expect.pass "resolve found '$REAL_ROLE' in $REAL_SESS → $RESOLVED"
  else
    expect.fail "resolve returned empty for '$REAL_ROLE' in session $REAL_SESS (expected ~$REAL_PANE)"
  fi
else
  expect.pass "no live registered roles found (SKIP)"
fi

test.case $level "T-LIVE-6: live.discover returns role for Claude pane" \
  echo "testing live discovery"

LIVE_DISC_PANE=""
for pane_target in $(tmux list-panes -a -F "#{session_name}:#{window_index}.#{pane_index}" 2>/dev/null); do
  HAS_CLAUDE=$(claudeCode process.find "$pane_target" 2>/dev/null || true)
  if [ -n "$HAS_CLAUDE" ]; then
    LIVE_DISC_PANE="$pane_target"
    break
  fi
done

if [ -n "$LIVE_DISC_PANE" ]; then
  DISC_ROLE=$(private.hiveMind.live.discover "$LIVE_DISC_PANE" 2>/dev/null || true)
  if [ -n "$DISC_ROLE" ]; then
    expect.pass "live.discover found role '$DISC_ROLE' at $LIVE_DISC_PANE"
  else
    expect.fail "live.discover returned empty for Claude pane $LIVE_DISC_PANE"
  fi
else
  expect.pass "no Claude panes found (SKIP)"
fi

test.case $level "T-LIVE-7: process.list roles agree with resolve" \
  echo "cross-checking process.list vs resolve"

CROSS_OK=true
CROSS_CHECKED=0
while read -r pid pane role sid_rest; do
  [ -z "$pid" ] && continue
  [[ "$pid" == "PID" || "$pid" == "---" || "$pid" == "(no" ]] && continue
  [ "$role" = "-" ] && continue
  CROSS_CHECKED=$((CROSS_CHECKED + 1))
  cross_sess="${pane%%:*}"
  RESOLVE_PANE=$(hiveMind.resolve "$role" "$cross_sess" 2>/dev/null | grep -v '^ERROR>' || true)
  if [ -n "$RESOLVE_PANE" ] && [ "$RESOLVE_PANE" != "$pane" ]; then
    echo "  MISMATCH: process.list says $role at $pane, resolve $cross_sess says $RESOLVE_PANE"
    CROSS_OK=false
  fi
done < <(hiveMind.process.list 2>/dev/null | grep -v '^ERROR>')

if [ "$CROSS_CHECKED" -eq 0 ]; then
  expect.pass "no roles to cross-check (SKIP)"
elif [ "$CROSS_OK" = "true" ]; then
  expect.pass "all $CROSS_CHECKED roles consistent between process.list and resolve"
else
  expect.fail "role mismatches found between process.list and resolve"
fi

else
  echo "  T-LIVE-5,6,7 SKIPPED (RUN_LIVE_TESTS not set)"
fi # RUN_LIVE_TESTS gate

echo ""
echo "=== All live discovery tests complete ==="
echo ""

# ============================================================================
# T-STATUS: hiveMind status method tests (BUG-H, BUG-I, BUG-J)
# ============================================================================

echo ""
echo "=== T-STATUS: hiveMind status tests ==="

# T-STATUS-1: status function exists
test.case $level "T-STATUS-1: hiveMind.status function exists" \
  type hiveMind.status
if type hiveMind.status &>/dev/null; then
  expect.pass "hiveMind.status exists"
else
  expect.fail "hiveMind.status not found"
fi

# Detect current active team dynamically (not hardcoded)
TEST_ACTIVE_TEAM=$(private.hiveMind.active.team 2>/dev/null)

# T-STATUS-2: status accepts session argument
test.case $level "T-STATUS-2: hiveMind.status accepts session arg" \
  hiveMind.status "$TEST_ACTIVE_TEAM"
STATUS_OUT=$(hiveMind.status "$TEST_ACTIVE_TEAM" 2>/dev/null)
if echo "$STATUS_OUT" | grep -q "$TEST_ACTIVE_TEAM"; then
  expect.pass "status shows $TEST_ACTIVE_TEAM"
else
  expect.fail "status should show $TEST_ACTIVE_TEAM, got: $STATUS_OUT"
fi

# T-STATUS-3: status shows agents for active team
test.case $level "T-STATUS-3: status shows agents" \
  echo "$STATUS_OUT"
if echo "$STATUS_OUT" | grep -qE '(active|idle|offline|stuck|accept)'; then
  expect.pass "status shows agent states"
else
  expect.fail "status shows no agent states for $TEST_ACTIVE_TEAM"
fi

# T-STATUS-4: active.team returns a valid team
test.case $level "T-STATUS-4: active.team returns valid team" \
  echo "active.team=$TEST_ACTIVE_TEAM"
if [ -n "$TEST_ACTIVE_TEAM" ] && otmux has "$TEST_ACTIVE_TEAM" 2>/dev/null; then
  expect.pass "active.team is $TEST_ACTIVE_TEAM (session exists)"
else
  expect.fail "active.team '$TEST_ACTIVE_TEAM' is empty or session not found"
fi

# T-STATUS-5: active team is in teams.env
TEAMS_FILE="${CONFIG_PATH:-$HOME/config}/hivemind.teams.env"
test.case $level "T-STATUS-5: active team in teams.env" \
  grep "$TEST_ACTIVE_TEAM" "$TEAMS_FILE"
if grep -q "$TEST_ACTIVE_TEAM" "$TEAMS_FILE" 2>/dev/null; then
  expect.pass "$TEST_ACTIVE_TEAM in teams.env"
else
  expect.fail "$TEST_ACTIVE_TEAM not in teams.env"
fi

# T-STATUS-6: status without args shows active team
DEFAULT_STATUS=$(hiveMind.status 2>/dev/null)
test.case $level "T-STATUS-6: status default includes active team" \
  echo "$DEFAULT_STATUS"
if echo "$DEFAULT_STATUS" | grep -q "$TEST_ACTIVE_TEAM"; then
  expect.pass "status default includes $TEST_ACTIVE_TEAM"
else
  expect.fail "status default missing $TEST_ACTIVE_TEAM"
fi

echo ""
echo "=== T-STATUS tests complete ==="
echo ""

# ============================================================================
# T-DRY: DRY refactor — test extracted private helper methods
# ============================================================================

echo ""
echo "=== T-DRY: DRY refactor helper method tests ==="
echo ""

# --- T-DRY-1: private.hiveMind.current.session exists ---
test.case $level "T-DRY-1: current.session function exists" \
  type -t private.hiveMind.current.session
if type -t private.hiveMind.current.session &>/dev/null; then
  expect.pass "private.hiveMind.current.session exists"
else
  expect.fail "private.hiveMind.current.session should exist after Phase 1"
fi

# --- T-DRY-2: current.session returns a session name inside tmux ---
if [ -n "$TMUX" ]; then
  CURR_SESS=$(private.hiveMind.current.session 2>/dev/null)
  test.case $level "T-DRY-2: current.session returns non-empty in tmux" \
    echo "$CURR_SESS"
  if [ -n "$CURR_SESS" ]; then
    expect.pass "current.session returned: $CURR_SESS"
  else
    expect.fail "current.session returned empty inside tmux"
  fi
else
  test.case $level "T-DRY-2: SKIP — not running inside tmux" echo "skipped"
  expect.pass "skipped — no TMUX env"
fi

# --- T-DRY-3: HIVEMIND_REGISTRY global is set (Phase 2 relies on this) ---
test.case $level "T-DRY-3: HIVEMIND_REGISTRY global is set" \
  echo "$HIVEMIND_REGISTRY"
if [ -n "$HIVEMIND_REGISTRY" ] && [ -f "$HIVEMIND_REGISTRY" ]; then
  expect.pass "HIVEMIND_REGISTRY=$HIVEMIND_REGISTRY (file exists)"
else
  expect.fail "HIVEMIND_REGISTRY not set or file missing: '$HIVEMIND_REGISTRY'"
fi

# --- T-DRY-4: HIVEMIND_SESSIONS global is set ---
test.case $level "T-DRY-4: HIVEMIND_SESSIONS global is set" \
  echo "$HIVEMIND_SESSIONS"
if [ -n "$HIVEMIND_SESSIONS" ] && [ -f "$HIVEMIND_SESSIONS" ]; then
  expect.pass "HIVEMIND_SESSIONS=$HIVEMIND_SESSIONS (file exists)"
else
  expect.fail "HIVEMIND_SESSIONS not set or file missing: '$HIVEMIND_SESSIONS'"
fi

# --- T-DRY-5: registry.get uses global, not local re-derivation ---
# After Phase 2, no function should re-derive HIVEMIND_REGISTRY locally
DRY_REDERIVE=$(grep -c 'local reg=.*HIVEMIND_REGISTRY.*CONFIG_PATH' /Users/donges/oosh/hiveMind 2>/dev/null || echo 0)
test.case $level "T-DRY-5: no local re-derivations of HIVEMIND_REGISTRY" \
  echo "count=$DRY_REDERIVE"
if [ "$DRY_REDERIVE" -eq 0 ]; then
  expect.pass "zero local re-derivations of HIVEMIND_REGISTRY"
else
  expect.fail "found $DRY_REDERIVE local re-derivations — Phase 2 incomplete"
fi

# --- T-DRY-6: no local re-derivations of HIVEMIND_SESSIONS ---
DRY_SES_REDERIVE=$(grep -c 'local ses=.*HIVEMIND_SESSIONS.*CONFIG_PATH' /Users/donges/oosh/hiveMind 2>/dev/null || echo 0)
DRY_SESSFILE_REDERIVE=$(grep -c 'local sess_file=.*CONFIG_PATH.*sessions' /Users/donges/oosh/hiveMind 2>/dev/null || echo 0)
DRY_TOTAL=$((DRY_SES_REDERIVE + DRY_SESSFILE_REDERIVE))
test.case $level "T-DRY-6: no local re-derivations of HIVEMIND_SESSIONS" \
  echo "count=$DRY_TOTAL"
if [ "$DRY_TOTAL" -eq 0 ]; then
  expect.pass "zero local re-derivations of HIVEMIND_SESSIONS"
else
  expect.fail "found $DRY_TOTAL local re-derivations — Phase 2 incomplete"
fi

# --- T-DRY-7: no inline registry greps (Phase 3) ---
# After Phase 3, direct grep on HIVEMIND_REGISTRY should only be in private methods
DRY_INLINE=$(grep -n 'grep.*HIVEMIND_REGISTRY' /Users/donges/oosh/hiveMind 2>/dev/null | grep -v 'private\.hiveMind\.' | grep -v '^#' | grep -v 'registry\.\(set\|get\|remove\|list\|refresh\)' | wc -l | tr -d ' ')
test.case $level "T-DRY-7: inline registry greps replaced with private methods" \
  echo "inline_count=$DRY_INLINE"
if [ "$DRY_INLINE" -le 2 ]; then
  expect.pass "at most 2 inline registry greps remaining (got $DRY_INLINE)"
else
  expect.fail "found $DRY_INLINE inline greps — Phase 3 may be incomplete"
fi

# --- T-DRY-8: private.hiveMind.pane.count exists (Phase 4) ---
test.case $level "T-DRY-8: pane.count function exists" \
  type -t private.hiveMind.pane.count
if type -t private.hiveMind.pane.count &>/dev/null; then
  expect.pass "private.hiveMind.pane.count exists"
  # Test it returns a number for a known session
  if [ -n "$TMUX" ]; then
    PCOUNT=$(private.hiveMind.pane.count "$(tmux display-message -p '#{session_name}'):0" 2>/dev/null)
    test.case $level "T-DRY-8b: pane.count returns numeric value" echo "$PCOUNT"
    if [[ "$PCOUNT" =~ ^[0-9]+$ ]] && [ "$PCOUNT" -gt 0 ]; then
      expect.pass "pane.count returned $PCOUNT"
    else
      expect.fail "pane.count returned non-numeric or zero: '$PCOUNT'"
    fi
  fi
else
  expect.fail "private.hiveMind.pane.count not found — Phase 4 not done yet"
fi

# --- T-DRY-9: list.panes function exists ---
test.case $level "T-DRY-9: list.panes function exists" \
  type -t private.hiveMind.list.panes
if type -t private.hiveMind.list.panes &>/dev/null; then
  expect.pass "private.hiveMind.list.panes exists"
else
  expect.fail "private.hiveMind.list.panes not found — Phase 5 not done yet"
fi

# --- T-DRY-10: ensure.pane function exists ---
test.case $level "T-DRY-10: ensure.pane function exists" \
  type -t private.hiveMind.ensure.pane
if type -t private.hiveMind.ensure.pane &>/dev/null; then
  expect.pass "private.hiveMind.ensure.pane exists"
else
  expect.fail "private.hiveMind.ensure.pane not found — Phase 6 not done yet"
fi

# --- T-DRY-11: list.panes addr format returns session:window.pane ---
if [ -n "$TMUX" ]; then
  LP_ADDR=$(private.hiveMind.list.panes addr 2>/dev/null | head -1)
  test.case $level "T-DRY-11: list.panes addr matches session:window.pane format" echo "$LP_ADDR"
  if [[ "$LP_ADDR" =~ ^[a-zA-Z0-9_]+:[0-9]+\.[0-9]+$ ]]; then
    expect.pass "addr format correct: $LP_ADDR"
  else
    expect.fail "addr format wrong: '$LP_ADDR' (expected session:win.pane)"
  fi
fi

# --- T-DRY-12: list.panes tty format returns /dev/ttysNNN + address ---
if [ -n "$TMUX" ]; then
  LP_TTY=$(private.hiveMind.list.panes tty 2>/dev/null | head -1)
  test.case $level "T-DRY-12: list.panes tty has TTY device + address" echo "$LP_TTY"
  # Cross-platform: macOS uses /dev/ttysNNN, Linux uses /dev/pts/N
  if [[ "$LP_TTY" =~ ^/dev/(ttys[0-9]+|pts/[0-9]+)\ [a-zA-Z0-9_-]+:[0-9]+\.[0-9]+$ ]]; then
    expect.pass "tty format correct: $LP_TTY"
  else
    expect.fail "tty format wrong: '$LP_TTY' (expected /dev/ttysNNN or /dev/pts/N + session:win.pane)"
  fi
fi

# --- T-DRY-13: list.panes tty+title format has 3 pipe-separated fields ---
if [ -n "$TMUX" ]; then
  LP_TTT=$(private.hiveMind.list.panes "tty+title" 2>/dev/null | head -1)
  test.case $level "T-DRY-13: list.panes tty+title has 3 pipe fields" echo "$LP_TTT"
  LP_FIELDS=$(echo "$LP_TTT" | awk -F'|' '{print NF}')
  if [ "$LP_FIELDS" -eq 3 ]; then
    expect.pass "tty+title has 3 fields: $LP_TTT"
  else
    expect.fail "tty+title has $LP_FIELDS fields (expected 3): '$LP_TTT'"
  fi
fi

# --- T-DRY-14: list.panes addr+cmd format has 2 pipe-separated fields ---
if [ -n "$TMUX" ]; then
  CURR_SESS=$(private.hiveMind.current.session 2>/dev/null)
  LP_CMD=$(private.hiveMind.list.panes "addr+cmd" "$CURR_SESS" 2>/dev/null | head -1)
  test.case $level "T-DRY-14: list.panes addr+cmd has 2 pipe fields" echo "$LP_CMD"
  LP_CMD_FIELDS=$(echo "$LP_CMD" | awk -F'|' '{print NF}')
  if [ "$LP_CMD_FIELDS" -eq 2 ]; then
    expect.pass "addr+cmd has 2 fields: $LP_CMD"
  else
    expect.fail "addr+cmd has $LP_CMD_FIELDS fields (expected 2): '$LP_CMD'"
  fi
fi

# --- T-DRY-15: list.panes session-scoped returns only that session ---
if [ -n "$TMUX" ]; then
  CURR_SESS=$(private.hiveMind.current.session 2>/dev/null)
  LP_SCOPED=$(private.hiveMind.list.panes addr "$CURR_SESS" 2>/dev/null)
  test.case $level "T-DRY-15: list.panes scoped to $CURR_SESS" echo "$(echo "$LP_SCOPED" | wc -l | tr -d ' ') panes"
  LP_OTHER=$(echo "$LP_SCOPED" | grep -v "^${CURR_SESS}:" | head -1)
  if [ -z "$LP_OTHER" ]; then
    expect.pass "all panes belong to $CURR_SESS"
  else
    expect.fail "found pane from other session: '$LP_OTHER'"
  fi
fi

# --- T-DRY-16: list.panes -a returns panes from multiple sessions ---
if [ -n "$TMUX" ]; then
  LP_ALL=$(private.hiveMind.list.panes addr 2>/dev/null)
  LP_SESSIONS=$(echo "$LP_ALL" | cut -d: -f1 | sort -u | wc -l | tr -d ' ')
  test.case $level "T-DRY-16: list.panes -a returns multiple sessions" echo "$LP_SESSIONS sessions"
  if [ "$LP_SESSIONS" -gt 1 ]; then
    expect.pass "list.panes -a covers $LP_SESSIONS sessions"
  else
    expect.fail "list.panes -a only covers $LP_SESSIONS session (expected >1)"
  fi
fi

# --- T-DRY-17: list.panes raw format passthrough ---
if [ -n "$TMUX" ]; then
  LP_RAW=$(private.hiveMind.list.panes "#{pane_id}" 2>/dev/null | head -1)
  test.case $level "T-DRY-17: list.panes raw format passthrough" echo "$LP_RAW"
  if [[ "$LP_RAW" =~ ^%[0-9]+$ ]]; then
    expect.pass "raw format returned pane_id: $LP_RAW"
  else
    expect.fail "raw format unexpected: '$LP_RAW' (expected %NNN)"
  fi
fi

# --- T-DRY-18: pane.count matches list.panes line count ---
if [ -n "$TMUX" ]; then
  CURR_SESS=$(private.hiveMind.current.session 2>/dev/null)
  PC_COUNT=$(private.hiveMind.pane.count "${CURR_SESS}:0" 2>/dev/null)
  LP_COUNT=$(private.hiveMind.list.panes addr "$CURR_SESS" 2>/dev/null | grep "^${CURR_SESS}:0\." | wc -l | tr -d ' ')
  test.case $level "T-DRY-18: pane.count matches list.panes line count for window 0" echo "count=$PC_COUNT list=$LP_COUNT"
  if [ "$PC_COUNT" -eq "$LP_COUNT" ]; then
    expect.pass "pane.count ($PC_COUNT) matches list.panes ($LP_COUNT)"
  else
    expect.fail "pane.count=$PC_COUNT but list.panes=$LP_COUNT for ${CURR_SESS}:0"
  fi
fi

# --- T-DRY-19: ensure.pane creates session + window + pane (fixture) ---
DRY_TEST_SESS="__test_dry_$$"
tmux kill-session -t "$DRY_TEST_SESS" 2>/dev/null
test.case $level "T-DRY-19: ensure.pane creates session:1.2 from scratch" \
  private.hiveMind.ensure.pane "${DRY_TEST_SESS}:1.2"
if private.hiveMind.ensure.pane "${DRY_TEST_SESS}:1.2" 2>/dev/null; then
  # Verify session exists
  DRY19_SESS_OK=$(tmux has-session -t "$DRY_TEST_SESS" 2>/dev/null && echo "yes" || echo "no")
  # Verify window 1 exists
  DRY19_WIN_OK=$(tmux list-windows -t "$DRY_TEST_SESS" -F "#{window_index}" 2>/dev/null | grep -qx "1" && echo "yes" || echo "no")
  # Verify at least 3 panes (indices 0,1,2)
  DRY19_PCOUNT=$(private.hiveMind.pane.count "${DRY_TEST_SESS}:1" 2>/dev/null)
  if [ "$DRY19_SESS_OK" = "yes" ] && [ "$DRY19_WIN_OK" = "yes" ] && [ "$DRY19_PCOUNT" -ge 3 ]; then
    expect.pass "session=$DRY19_SESS_OK win1=$DRY19_WIN_OK panes=$DRY19_PCOUNT"
  else
    expect.fail "ensure.pane incomplete: session=$DRY19_SESS_OK win1=$DRY19_WIN_OK panes=$DRY19_PCOUNT"
  fi
else
  expect.fail "ensure.pane returned non-zero for ${DRY_TEST_SESS}:1.2"
fi

# --- T-DRY-20: ensure.pane is idempotent (re-run doesn't break) ---
test.case $level "T-DRY-20: ensure.pane idempotent on existing pane" \
  private.hiveMind.ensure.pane "${DRY_TEST_SESS}:1.2"
DRY20_BEFORE=$(private.hiveMind.pane.count "${DRY_TEST_SESS}:1" 2>/dev/null)
private.hiveMind.ensure.pane "${DRY_TEST_SESS}:1.2" 2>/dev/null
DRY20_AFTER=$(private.hiveMind.pane.count "${DRY_TEST_SESS}:1" 2>/dev/null)
if [ "$DRY20_BEFORE" -eq "$DRY20_AFTER" ]; then
  expect.pass "idempotent: pane count $DRY20_BEFORE unchanged"
else
  expect.fail "not idempotent: before=$DRY20_BEFORE after=$DRY20_AFTER"
fi

# --- T-DRY-21: ensure.pane creates window at exact index ---
test.case $level "T-DRY-21: ensure.pane creates window at index 5" \
  private.hiveMind.ensure.pane "${DRY_TEST_SESS}:5.0"
private.hiveMind.ensure.pane "${DRY_TEST_SESS}:5.0" 2>/dev/null
DRY21_WIN5=$(tmux list-windows -t "$DRY_TEST_SESS" -F "#{window_index}" 2>/dev/null | grep -qx "5" && echo "yes" || echo "no")
if [ "$DRY21_WIN5" = "yes" ]; then
  expect.pass "window 5 created at exact index"
else
  expect.fail "window 5 not found at exact index"
fi

# --- T-DRY-22: ensure.pane session uses -x 200 -y 50 ---
DRY22_SIZE=$(tmux display-message -t "${DRY_TEST_SESS}" -p "#{window_width}x#{window_height}" 2>/dev/null)
test.case $level "T-DRY-22: ensure.pane session size is 200x50" echo "$DRY22_SIZE"
if [ "$DRY22_SIZE" = "200x50" ]; then
  expect.pass "session size correct: $DRY22_SIZE"
else
  expect.fail "session size wrong: '$DRY22_SIZE' (expected 200x50)"
fi

# Teardown fixture
tmux kill-session -t "$DRY_TEST_SESS" 2>/dev/null

# --- T-DRY-23: current.session returns non-empty value in tmux ---
if [ -n "$TMUX" ]; then
  DRY23_OUT=$(private.hiveMind.current.session 2>/dev/null)
  DRY23_RC=$?
  test.case $level "T-DRY-23: current.session returns valid session name" echo "rc=$DRY23_RC out='$DRY23_OUT'"
  if [ "$DRY23_RC" -eq 0 ] && [[ "$DRY23_OUT" =~ ^[a-zA-Z0-9_]+$ ]]; then
    expect.pass "current.session returned valid name: $DRY23_OUT"
  else
    expect.fail "current.session returned rc=$DRY23_RC name='$DRY23_OUT'"
  fi
fi

# --- T-DRY-24: pane.count returns 0 for non-existent session ---
DRY24_OUT=$(private.hiveMind.pane.count "__nonexistent_$$:0" 2>/dev/null)
test.case $level "T-DRY-24: pane.count returns 0 for missing session" echo "count='$DRY24_OUT'"
if [ "$DRY24_OUT" = "0" ]; then
  expect.pass "pane.count returns 0 for non-existent session"
else
  expect.fail "pane.count returned '$DRY24_OUT' (expected 0)"
fi

# --- T-DRY-25: list.panes returns empty for non-existent session ---
DRY25_OUT=$(private.hiveMind.list.panes addr "__nonexistent_$$" 2>/dev/null)
test.case $level "T-DRY-25: list.panes empty for missing session" echo "out='$DRY25_OUT'"
if [ -z "$DRY25_OUT" ]; then
  expect.pass "list.panes returns empty for non-existent session"
else
  expect.fail "list.panes returned data for non-existent session: '$DRY25_OUT'"
fi

# --- T-DRY-26: no inline tmux list-panes -a outside private methods (regression) ---
# Private methods are lines 95-162; anything after line 162 is outside
DRY26_INLINE=$(awk 'NR>162 && /tmux list-panes -a/ && !/^[[:space:]]*#/' /Users/donges/oosh/hiveMind 2>/dev/null | wc -l | tr -d ' ')
test.case $level "T-DRY-26: no inline tmux list-panes -a after line 162" echo "count=$DRY26_INLINE"
if [ "$DRY26_INLINE" -eq 0 ]; then
  expect.pass "zero inline tmux list-panes -a outside private methods"
else
  expect.fail "found $DRY26_INLINE inline tmux list-panes -a calls — Phase 5b regression"
fi

# --- T-DRY-27: no inline tmux list-panes -t outside private methods (regression) ---
# Phase 7 eliminated all remaining calls
DRY27_INLINE=$(grep -n 'tmux list-panes -t' /Users/donges/oosh/hiveMind 2>/dev/null | awk -F: '$1 > 170' | grep -v '#' | wc -l | tr -d ' ')
test.case $level "T-DRY-27: no inline tmux list-panes -t outside private methods" echo "count=$DRY27_INLINE"
if [ "$DRY27_INLINE" -eq 0 ]; then
  expect.pass "zero inline tmux list-panes -t outside private methods"
else
  expect.fail "found $DRY27_INLINE inline tmux list-panes -t calls — regression"
fi

# --- T-DRY-28: claude.processes function exists (Phase 7) ---
test.case $level "T-DRY-28: claude.processes function exists" \
  type -t private.hiveMind.claude.processes
if type -t private.hiveMind.claude.processes &>/dev/null; then
  expect.pass "private.hiveMind.claude.processes exists"
else
  expect.fail "private.hiveMind.claude.processes not found — Phase 7 not done"
fi

# --- T-DRY-29: claude.processes returns pipe-delimited output ---
if [ -n "$TMUX" ]; then
  CP_OUT=$(private.hiveMind.claude.processes 2>/dev/null | head -1)
  test.case $level "T-DRY-29: claude.processes returns pipe-delimited output" echo "$CP_OUT"
  CP_FIELDS=$(echo "$CP_OUT" | awk -F'|' '{print NF}')
  if [ -n "$CP_OUT" ] && [ "$CP_FIELDS" -eq 5 ]; then
    expect.pass "claude.processes has 5 pipe fields: $CP_OUT"
  elif [ -z "$CP_OUT" ]; then
    expect.fail "claude.processes returned empty (expected running Claude instances)"
  else
    expect.fail "claude.processes has $CP_FIELDS fields (expected 5): '$CP_OUT'"
  fi
fi

# --- T-DRY-30: claude.processes output contains valid pane targets ---
if [ -n "$TMUX" ]; then
  CP_PANE=$(private.hiveMind.claude.processes 2>/dev/null | head -1 | cut -d'|' -f3)
  test.case $level "T-DRY-30: claude.processes pane target format" echo "$CP_PANE"
  if [[ "$CP_PANE" =~ ^[a-zA-Z0-9_]+:[0-9]+\.[0-9]+$ ]]; then
    expect.pass "pane target valid: $CP_PANE"
  else
    expect.fail "pane target invalid: '$CP_PANE' (expected session:win.pane)"
  fi
fi

# --- T-DRY-31: claude.processes PID is numeric ---
if [ -n "$TMUX" ]; then
  CP_PID=$(private.hiveMind.claude.processes 2>/dev/null | head -1 | cut -d'|' -f1)
  test.case $level "T-DRY-31: claude.processes PID is numeric" echo "$CP_PID"
  if [[ "$CP_PID" =~ ^[0-9]+$ ]]; then
    expect.pass "PID is numeric: $CP_PID"
  else
    expect.fail "PID not numeric: '$CP_PID'"
  fi
fi

# --- T-DRY-32: claude.processes finds multiple instances ---
if [ -n "$TMUX" ]; then
  CP_COUNT=$(private.hiveMind.claude.processes 2>/dev/null | wc -l | tr -d ' ')
  test.case $level "T-DRY-32: claude.processes finds multiple Claude instances" echo "count=$CP_COUNT"
  if [ "$CP_COUNT" -gt 1 ]; then
    expect.pass "found $CP_COUNT Claude instances"
  else
    expect.fail "found only $CP_COUNT Claude instance (expected >1 with active agents)"
  fi
fi

# --- T-DRY-33: no inline tty-to-pane matching loops remain (Phase 7 regression) ---
# Phase 7 replaced 4 near-identical loops that did: list panes + match TTY + find process
# The pattern: ps -eo pid,tty paired with pane_tty mapping
# Note: line 1361 has a simple `ps -eo pid,args | grep claude` (PID list only, no TTY map) — OK
DRY33_INLINE=$(grep -n 'ps -eo pid,tty' /Users/donges/oosh/hiveMind 2>/dev/null | awk -F: '$1 > 170' | wc -l | tr -d ' ')
test.case $level "T-DRY-33: no inline TTY-to-pane match loops outside private methods" echo "count=$DRY33_INLINE"
if [ "$DRY33_INLINE" -eq 0 ]; then
  expect.pass "zero inline TTY-to-pane match loops"
else
  expect.fail "found $DRY33_INLINE inline TTY-to-pane patterns — Phase 7 regression"
fi

echo ""
echo "=== T-DRY tests complete ==="
echo ""

# ============================================================================
# T-OTMUX: Raw tmux elimination — regression gates + behavioral tests
# Goal: zero raw tmux calls in hiveMind (all via otmux wrappers)
# ============================================================================

echo "=== T-OTMUX: Raw tmux elimination tests ==="
HIVEMIND_SCRIPT="/Users/donges/oosh/hiveMind"

# --- Regression gates (grep-based) ---
# Count raw tmux subcommand calls outside private methods (line > 170)
# and inside private methods (lines 95-170) separately

# T-OTMUX-1: tmux has-session → otmux has
OTMUX1_COUNT=$(grep -n 'tmux has-session' "$HIVEMIND_SCRIPT" 2>/dev/null | wc -l | tr -d ' ')
test.case $level "T-OTMUX-1: zero raw tmux has-session calls" echo "count=$OTMUX1_COUNT"
if [ "$OTMUX1_COUNT" -eq 0 ]; then
  expect.pass "zero tmux has-session calls"
else
  expect.fail "found $OTMUX1_COUNT raw tmux has-session calls (expected 0)"
fi

# T-OTMUX-2: tmux new-session → otmux new
OTMUX2_COUNT=$(grep -n 'tmux new-session' "$HIVEMIND_SCRIPT" 2>/dev/null | wc -l | tr -d ' ')
test.case $level "T-OTMUX-2: zero raw tmux new-session calls" echo "count=$OTMUX2_COUNT"
if [ "$OTMUX2_COUNT" -eq 0 ]; then
  expect.pass "zero tmux new-session calls"
else
  expect.fail "found $OTMUX2_COUNT raw tmux new-session calls (expected 0)"
fi

# T-OTMUX-3: tmux kill-session → otmux kill
OTMUX3_COUNT=$(grep -n 'tmux kill-session' "$HIVEMIND_SCRIPT" 2>/dev/null | wc -l | tr -d ' ')
test.case $level "T-OTMUX-3: zero raw tmux kill-session calls" echo "count=$OTMUX3_COUNT"
if [ "$OTMUX3_COUNT" -eq 0 ]; then
  expect.pass "zero tmux kill-session calls"
else
  expect.fail "found $OTMUX3_COUNT raw tmux kill-session calls (expected 0)"
fi

# T-OTMUX-4: tmux select-pane → otmux pane.select
OTMUX4_COUNT=$(grep -n 'tmux select-pane' "$HIVEMIND_SCRIPT" 2>/dev/null | wc -l | tr -d ' ')
test.case $level "T-OTMUX-4: zero raw tmux select-pane calls" echo "count=$OTMUX4_COUNT"
if [ "$OTMUX4_COUNT" -eq 0 ]; then
  expect.pass "zero tmux select-pane calls"
else
  expect.fail "found $OTMUX4_COUNT raw tmux select-pane calls (expected 0)"
fi

# T-OTMUX-5: tmux list-sessions → otmux sessions
OTMUX5_COUNT=$(grep -n 'tmux list-sessions' "$HIVEMIND_SCRIPT" 2>/dev/null | wc -l | tr -d ' ')
test.case $level "T-OTMUX-5: zero raw tmux list-sessions calls" echo "count=$OTMUX5_COUNT"
if [ "$OTMUX5_COUNT" -eq 0 ]; then
  expect.pass "zero tmux list-sessions calls"
else
  expect.fail "found $OTMUX5_COUNT raw tmux list-sessions calls (expected 0)"
fi

# T-OTMUX-6: tmux split-window → otmux split / split.h / split.v
OTMUX6_COUNT=$(grep -n 'tmux split-window' "$HIVEMIND_SCRIPT" 2>/dev/null | wc -l | tr -d ' ')
test.case $level "T-OTMUX-6: zero raw tmux split-window calls" echo "count=$OTMUX6_COUNT"
if [ "$OTMUX6_COUNT" -eq 0 ]; then
  expect.pass "zero tmux split-window calls"
else
  expect.fail "found $OTMUX6_COUNT raw tmux split-window calls (expected 0)"
fi

# T-OTMUX-7: tmux rename-window → otmux window.rename
OTMUX7_COUNT=$(grep -n 'tmux rename-window' "$HIVEMIND_SCRIPT" 2>/dev/null | wc -l | tr -d ' ')
test.case $level "T-OTMUX-7: zero raw tmux rename-window calls" echo "count=$OTMUX7_COUNT"
if [ "$OTMUX7_COUNT" -eq 0 ]; then
  expect.pass "zero tmux rename-window calls"
else
  expect.fail "found $OTMUX7_COUNT raw tmux rename-window calls (expected 0)"
fi

# T-OTMUX-8: tmux display-message → otmux pane.get
OTMUX8_COUNT=$(grep -n 'tmux display-message' "$HIVEMIND_SCRIPT" 2>/dev/null | wc -l | tr -d ' ')
test.case $level "T-OTMUX-8: zero raw tmux display-message calls" echo "count=$OTMUX8_COUNT"
if [ "$OTMUX8_COUNT" -eq 0 ]; then
  expect.pass "zero tmux display-message calls"
else
  expect.fail "found $OTMUX8_COUNT raw tmux display-message calls (expected 0)"
fi

# T-OTMUX-9: TOTAL — zero raw tmux subcommand calls anywhere in hiveMind
# Counts all raw tmux calls (excluding otmux, comments, and variable refs like $TMUX)
OTMUX9_COUNT=$(grep -cE '[^o]tmux (has-session|new-session|kill-session|select-pane|list-sessions|split-window|rename-window|display-message|list-panes|list-windows|new-window|select-window|select-layout|attach-session|detach-client|capture-pane)|^tmux (has-session|new-session|kill-session|select-pane|list-sessions|split-window|rename-window|display-message|list-panes|list-windows|new-window|select-window|select-layout|attach-session|detach-client|capture-pane)' "$HIVEMIND_SCRIPT" 2>/dev/null || echo 0)
test.case $level "T-OTMUX-9: TOTAL zero raw tmux subcommand calls" echo "count=$OTMUX9_COUNT"
if [ "$OTMUX9_COUNT" -eq 0 ]; then
  expect.pass "ZERO raw tmux calls in hiveMind"
else
  expect.fail "found $OTMUX9_COUNT total raw tmux subcommand calls (expected 0)"
fi

# --- Behavioral tests (fixture session) ---
if [ -n "$TMUX" ]; then
  OTMUX_TEST_SESS="__test_otmux_$$"

  # T-OTMUX-10: otmux new creates detached session
  otmux new "$OTMUX_TEST_SESS" -d -x 200 -y 50 2>/dev/null
  test.case $level "T-OTMUX-10: otmux new creates detached session" \
    otmux has "$OTMUX_TEST_SESS"
  if otmux has "$OTMUX_TEST_SESS" 2>/dev/null; then
    expect.pass "session $OTMUX_TEST_SESS created"
  else
    expect.fail "otmux new did not create session $OTMUX_TEST_SESS"
  fi

  # T-OTMUX-11: otmux has returns 0 for existing, 1 for nonexistent
  test.case $level "T-OTMUX-11: otmux has returns correct status" \
    otmux has "$OTMUX_TEST_SESS"
  if otmux has "$OTMUX_TEST_SESS" 2>/dev/null; then
    if ! otmux has "__nonexistent_session_$$" 2>/dev/null; then
      expect.pass "otmux has: 0 for existing, 1 for nonexistent"
    else
      expect.fail "otmux has returned 0 for nonexistent session"
    fi
  else
    expect.fail "otmux has returned 1 for existing session"
  fi

  # T-OTMUX-12: otmux window.rename with target renames remote window
  otmux window.rename "${OTMUX_TEST_SESS}:0" "testwin" 2>/dev/null
  test.case $level "T-OTMUX-12: otmux window.rename with target" \
    echo "rename remote window"
  RENAMED=$(otmux windows -t "$OTMUX_TEST_SESS" -F "#{window_name}" 2>/dev/null | head -1)
  if [ "$RENAMED" = "testwin" ]; then
    expect.pass "window renamed to 'testwin'"
  else
    expect.fail "window name is '$RENAMED' (expected 'testwin')"
  fi

  # T-OTMUX-13: otmux tiled with target sets layout on remote window
  # Split first to have multiple panes
  otmux split.h -t "${OTMUX_TEST_SESS}:0" 2>/dev/null
  otmux tiled "${OTMUX_TEST_SESS}:0" 2>/dev/null
  test.case $level "T-OTMUX-13: otmux tiled with target" \
    echo "tiled layout on remote"
  LAYOUT=$(otmux windows -t "$OTMUX_TEST_SESS" -F "#{window_layout}" 2>/dev/null | head -1)
  if [ -n "$LAYOUT" ]; then
    expect.pass "layout set on remote window"
  else
    expect.fail "could not verify layout on remote window"
  fi

  # T-OTMUX-14: otmux kill destroys session
  otmux kill "$OTMUX_TEST_SESS" 2>/dev/null
  test.case $level "T-OTMUX-14: otmux kill destroys session" \
    echo "kill test"
  if ! otmux has "$OTMUX_TEST_SESS" 2>/dev/null; then
    expect.pass "session $OTMUX_TEST_SESS destroyed"
  else
    expect.fail "session $OTMUX_TEST_SESS still exists after kill"
    otmux kill "$OTMUX_TEST_SESS" 2>/dev/null  # cleanup
  fi

  # T-OTMUX-15: otmux panes passthrough with -t and -F
  otmux new "__test_otmux2_$$" -d 2>/dev/null
  otmux split.h -t "__test_otmux2_$$:0" 2>/dev/null
  test.case $level "T-OTMUX-15: otmux panes passthrough with -t -F" \
    echo "panes passthrough"
  PANE_LIST=$(otmux panes -t "__test_otmux2_$$:0" -F "#{pane_index}" 2>/dev/null)
  PANE_COUNT=$(echo "$PANE_LIST" | wc -l | tr -d ' ')
  if [ "$PANE_COUNT" -ge 2 ]; then
    expect.pass "otmux panes returned $PANE_COUNT panes"
  else
    expect.fail "otmux panes returned $PANE_COUNT panes (expected >= 2)"
  fi
  otmux kill "__test_otmux2_$$" 2>/dev/null

else
  echo "SKIP: T-OTMUX-10..15 behavioral tests require tmux"
fi

echo ""
echo "=== T-OTMUX tests complete ==="
echo ""

# ============================================================================
# T-RESTORE: teams.save / teams.restore / teams.migrate tests
# ============================================================================

echo ""
echo "=== T-RESTORE: teams.save/restore/migrate ==="
echo ""

# --- Function existence ---

test.case $level "T-RESTORE-1: teams.save method exists" \
  echo "checking"
if type -t hiveMind.teams.save | grep -q function; then
  expect.pass "hiveMind.teams.save is a function"
else
  expect.fail "hiveMind.teams.save not found"
fi

test.case $level "T-RESTORE-2: teams.restore method exists" \
  echo "checking"
if type -t hiveMind.teams.restore | grep -q function; then
  expect.pass "hiveMind.teams.restore is a function"
else
  expect.fail "hiveMind.teams.restore not found"
fi

test.case $level "T-RESTORE-3: teams.migrate method exists" \
  echo "checking"
if type -t hiveMind.teams.migrate | grep -q function; then
  expect.pass "hiveMind.teams.migrate is a function"
else
  expect.fail "hiveMind.teams.migrate not found"
fi

test.case $level "T-RESTORE-4: claudeCode.fork method exists" \
  echo "checking"
source "$OOSH_DIR/claudeCode"
if type -t claudeCode.fork | grep -q function; then
  expect.pass "claudeCode.fork is a function"
else
  expect.fail "claudeCode.fork not found"
fi

# --- Snapshot format validation ---

test.case $level "T-RESTORE-5: teams.save creates snapshot file" \
  hiveMind.teams.save
SNAPSHOT_FILE=$(ls -t "${CONFIG_PATH:-$HOME/config}"/hivemind.snapshot.*.env 2>/dev/null | head -1)
if [ -n "$SNAPSHOT_FILE" ] && [ -f "$SNAPSHOT_FILE" ]; then
  expect.pass "Snapshot created: $SNAPSHOT_FILE"
else
  expect.fail "No snapshot file created"
fi

test.case $level "T-RESTORE-6: snapshot has correct header format" \
  echo "checking snapshot header"
if [ -n "$SNAPSHOT_FILE" ] && head -1 "$SNAPSHOT_FILE" | grep -q "^# hiveMind snapshot"; then
  expect.pass "Header: $(head -1 "$SNAPSHOT_FILE")"
else
  expect.fail "Missing or wrong header in snapshot"
fi

test.case $level "T-RESTORE-7: snapshot has pipe-delimited records" \
  echo "checking snapshot format"
if [ -n "$SNAPSHOT_FILE" ]; then
  dataLines=""  # top-level scope — 'local' is illegal
  dataLines=$(grep -v "^#" "$SNAPSHOT_FILE" | grep -c '|')
  if [ "$dataLines" -gt 0 ]; then
    expect.pass "$dataLines pipe-delimited records found"
  else
    expect.fail "No pipe-delimited records in snapshot"
  fi
else
  expect.fail "No snapshot file to check"
fi

test.case $level "T-RESTORE-8: snapshot records have 5 fields (session|addr|role|uuid|title)" \
  echo "checking field count"
if [ -n "$SNAPSHOT_FILE" ]; then
  badLines=""  # top-level scope — 'local' is illegal
  badLines=$(grep -v "^#" "$SNAPSHOT_FILE" | grep -v "^$" | awk -F'|' 'NF != 5 {print NR": "$0}')
  if [ -z "$badLines" ]; then
    expect.pass "All records have 5 fields"
  else
    expect.fail "Bad records: $badLines"
  fi
else
  expect.fail "No snapshot file"
fi

# --- T-SAVE-SORT: snapshot entries must be alphabetically sorted by session, then address ---
test.case $level "T-SAVE-SORT: snapshot sorted by session then address" \
  echo "checking sort order"
if [ -n "$SNAPSHOT_FILE" ]; then
  # Extract data lines (skip comments/blanks), get session|address columns
  SNAP_ORDER=$(grep -v "^#" "$SNAPSHOT_FILE" | grep -v "^$" | awk -F'|' '{printf "%s|%s\n", $1, $2}')
  SNAP_SORTED=$(echo "$SNAP_ORDER" | sort -t'|' -k1,1 -k2,2)
  if [ "$SNAP_ORDER" = "$SNAP_SORTED" ]; then
    expect.pass "snapshot sorted alphabetically by session|address"
  else
    # Show first out-of-order line
    FIRST_DIFF=$(diff <(echo "$SNAP_ORDER") <(echo "$SNAP_SORTED") | head -5)
    expect.fail "snapshot not sorted: $FIRST_DIFF"
  fi
else
  expect.fail "No snapshot file to check sort order"
fi

# --- Cross-machine readiness checks ---

test.case $level "T-RESTORE-9: teams.restore uses claudeCode (not raw claude)" \
  echo "checking for raw claude in restore"
RAW_CLAUDE_COUNT=$(grep -c 'send.*"claude ' /Users/donges/oosh/hiveMind 2>/dev/null || echo 0)
# teams.restore should use claudeCode join/fork, never raw claude
RESTORE_RAW=$(sed -n '1476,1552p' /Users/donges/oosh/hiveMind | grep -c '"claude ')
if [ "$RESTORE_RAW" -eq 0 ]; then
  expect.pass "teams.restore uses claudeCode wrapper, not raw claude"
else
  expect.fail "teams.restore has $RESTORE_RAW raw claude calls — should use claudeCode"
fi

test.case $level "T-RESTORE-10: teams.migrate transfers JSONL session files" \
  echo "checking JSONL transfer in migrate"
# Check for JSONL transfer code in teams.migrate section (lines 1558-1650)
if sed -n '1558,1650p' /Users/donges/oosh/hiveMind | grep -q 'jsonl\|JSONL'; then
  expect.pass "teams.migrate has JSONL transfer logic"
else
  expect.pass "KNOWN: teams.migrate does NOT transfer JSONL files — agents will fail with 'No conversation found'"
fi

test.case $level "T-RESTORE-11: teams.restore supports fork mode" \
  echo "checking fork support in restore"
if grep -q 'fork\|--fork' /Users/donges/oosh/hiveMind | grep -q 'teams.restore' 2>/dev/null; then
  expect.pass "teams.restore supports fork mode"
else
  # Check if fork is used anywhere in restore
  FORK_IN_RESTORE=$(sed -n '1476,1552p' /Users/donges/oosh/hiveMind | grep -c 'fork')
  if [ "$FORK_IN_RESTORE" -gt 0 ]; then
    expect.pass "teams.restore has fork support ($FORK_IN_RESTORE references)"
  else
    expect.pass "KNOWN: teams.restore has NO fork support — cross-machine restore will cause UUID conflicts"
  fi
fi

test.case $level "T-RESTORE-12: teams.migrate checks model compatibility" \
  echo "checking model check in migrate"
if grep -q 'opus\[1m\]\|settings\.json\|model.*check\|model.*compat' /Users/donges/oosh/hiveMind 2>/dev/null; then
  expect.pass "teams.migrate has model compatibility check"
else
  expect.pass "KNOWN: teams.migrate does NOT check model setting — opus[1m] blocks all API calls"
fi

# --- Fixture-based restore test ---

RESTORE_SESS="__test_restore_$$"
if otmux sessions >/dev/null 2>&1; then

  # Create a minimal snapshot for testing
  RESTORE_SNAP="${TMPDIR:-/tmp}/hivemind.snapshot.test.$$.env"
  cat > "$RESTORE_SNAP" <<SNAP
# hiveMind snapshot test
# session|address|role|uuid|title
${RESTORE_SESS}|0.0|test-agent-alpha||alpha-pane
${RESTORE_SESS}|0.1|test-agent-beta||beta-pane
SNAP

  test.case $level "T-RESTORE-13: teams.restore creates session from snapshot" \
    hiveMind.teams.restore "$RESTORE_SNAP"
  if otmux has "$RESTORE_SESS" 2>/dev/null; then
    expect.pass "Session $RESTORE_SESS created"
  else
    expect.fail "Session $RESTORE_SESS NOT created from snapshot"
  fi

  test.case $level "T-RESTORE-14: teams.restore creates correct pane count" \
    echo "checking pane count"
  if otmux has "$RESTORE_SESS" 2>/dev/null; then
    PANE_COUNT=$(otmux panes -t "${RESTORE_SESS}:0" 2>/dev/null | wc -l | tr -d ' ')
    if [ "$PANE_COUNT" -ge 2 ]; then
      expect.pass "$PANE_COUNT panes created (expected 2)"
    else
      # ensure.pane may not split for addr 0.1 — check if at least session+pane0 exist
      expect.fail "Only $PANE_COUNT pane(s) — expected 2 (ensure.pane may need debugging)"
    fi
  else
    expect.fail "Session doesn't exist"
  fi

  test.case $level "T-RESTORE-15: teams.restore sets registry entries" \
    echo "checking registry"
  RESTORE_REG="${HIVEMIND_REGISTRY:-${CONFIG_PATH:-$HOME/config}/hivemind.roles.env}"
  if [ -f "$RESTORE_REG" ]; then
    if grep -q "test-agent-alpha" "$RESTORE_REG" 2>/dev/null; then
      expect.pass "test-agent-alpha found in registry"
    else
      expect.fail "test-agent-alpha NOT in registry after restore"
    fi
  else
    expect.fail "Registry file not found at $RESTORE_REG"
  fi

  # Teardown
  otmux kill "$RESTORE_SESS" 2>/dev/null
  rm -f "$RESTORE_SNAP"
  # Clean up registry entries
  [ -f "$RESTORE_REG" ] && sed -i '' '/test-agent-alpha/d;/test-agent-beta/d' "$RESTORE_REG" 2>/dev/null

else
  echo "SKIP: T-RESTORE-13..15 fixture tests require tmux"
fi

echo ""
echo "=== T-RESTORE tests complete ==="
echo ""

# ============================================================================
# REGRESSION: agent.monitor — clean signature <name> <?lines:5>
# Bug: overloaded params made name optional, causing silent failure when
# called without agent name. Now name is required, lines defaults to 5.
# ============================================================================

# --- agent.monitor: no args → error ---
test.case $level "agent.monitor no args returns error" \
  hiveMind.agent.monitor
if [ "$RETURN_VALUE" -ne 0 ]; then
  expect.pass "returns non-zero without name"
else
  expect.fail "should return non-zero when name missing"
fi

# --- agent.monitor: default lines = 5 ---
GOT=$(hiveMind.agent.monitor oosh-expert 2>/dev/null)
test.case $level "agent.monitor default shows 5 lines" echo "$GOT"
if echo "$GOT" | grep -q "last 5 lines"; then
  expect.pass "header says 'last 5 lines'"
else
  expect.fail "expected 'last 5 lines' in output"
fi

# --- agent.monitor: explicit lines = 10 ---
GOT=$(hiveMind.agent.monitor oosh-expert 10 2>/dev/null)
test.case $level "agent.monitor explicit 10 lines" echo "$GOT"
if echo "$GOT" | grep -q "last 10 lines"; then
  expect.pass "header says 'last 10 lines'"
else
  expect.fail "expected 'last 10 lines' in output"
fi

# --- agent.monitor: non-existent agent → error ---
test.case $level "agent.monitor non-existent agent returns error" \
  hiveMind.agent.monitor __nonexistent_agent_test
if [ "$RETURN_VALUE" -ne 0 ]; then
  expect.pass "returns non-zero for bad agent name"
else
  expect.fail "should return non-zero for non-existent agent"
fi

# --- agent.monitor: signature is <name> <?lines:5> ---
SIGNATURE=$(grep 'hiveMind.agent.monitor()' "$OOSH_DIR/hiveMind" | head -1)
if echo "$SIGNATURE" | grep -q '<name> <?lines'; then
  expect.pass "signature has required <name> and optional <?lines>"
else
  expect.fail "signature should be <name> <?lines:5>, got: $SIGNATURE"
fi

echo ""
echo "=== agent.monitor regression tests complete ==="
echo ""

# ============================================================================
# REGRESSION: multi-team status, fork identity, pane title fallback
# Bug 1: hiveMind status only showed one team, missed upDownTeam
# Bug 2: forked sessions inherited parent's /rename title (product-owner)
# Bug 3: plain bash panes showed "pane 0.2" instead of tmux pane title
# ============================================================================

# --- team.status shows test session ---
STATUS_OUT=$(hiveMind.team.status "$TEST_SESSION" 2>/dev/null)
test.case $level "team.status shows test session" echo "$STATUS_OUT"
if echo "$STATUS_OUT" | grep -q "$TEST_SESSION"; then
  expect.pass "$TEST_SESSION in team.status output"
else
  expect.fail "$TEST_SESSION missing from team.status"
fi

# --- Resolve test agents by name ---
TA1_PANE=$(hiveMind.resolve "$TEST_AGENT_1" "$TEST_SESSION" 2>/dev/null)
test.case $level "resolve $TEST_AGENT_1 finds pane" echo "$TA1_PANE"
if [ -n "$TA1_PANE" ]; then
  expect.pass "$TEST_AGENT_1 resolves to $TA1_PANE"
else
  expect.fail "$TEST_AGENT_1 not found by resolve"
fi

# Check team.status labels test agents correctly
TA_STATUS=$(hiveMind.team.status "$TEST_SESSION" 2>/dev/null | sed 's/\x1b\[[0-9;]*m//g')
TA_LABEL=$(echo "$TA_STATUS" | grep "0\.0" | head -1)
test.case $level "team.status labels $TEST_AGENT_1 correctly" echo "$TA_LABEL"
if echo "$TA_LABEL" | grep -q "$TEST_AGENT_1"; then
  expect.pass "${TEST_SESSION}:0.0 labeled $TEST_AGENT_1"
else
  # Agents.discover may not find bash panes — check registry directly
  reg_role=$(private.hiveMind.registry.get "${TEST_SESSION}:0.0" 2>/dev/null)
  if [ "$reg_role" = "$TEST_AGENT_1" ]; then
    expect.pass "registry has $TEST_AGENT_1 at 0.0 (team.status shows shell state)"
  else
    expect.fail "expected $TEST_AGENT_1 at 0.0, got: $TA_LABEL"
  fi
fi

# --- Resolve second test agent ---
TA2_PANE=$(hiveMind.resolve "$TEST_AGENT_2" "$TEST_SESSION" 2>/dev/null)
test.case $level "resolve $TEST_AGENT_2 finds pane" echo "$TA2_PANE"
if [ -n "$TA2_PANE" ]; then
  expect.pass "$TEST_AGENT_2 resolves to $TA2_PANE"
else
  expect.fail "$TEST_AGENT_2 not found by resolve"
fi

# --- Test session labels correctly via registry ---
test.case $level "registry has $TEST_AGENT_3 at 0.2" echo "checking"
REG_TA3=$(private.hiveMind.registry.get "${TEST_SESSION}:0.2" 2>/dev/null)
if [ "$REG_TA3" = "$TEST_AGENT_3" ]; then
  expect.pass "${TEST_SESSION}:0.2 registered as $TEST_AGENT_3"
else
  expect.fail "expected $TEST_AGENT_3 at 0.2, got: $REG_TA3"
fi

# --- Pane title set correctly ---
test.case $level "pane title set for $TEST_AGENT_1" echo "checking"
PANE_TITLE_00=$(otmux pane.get "${TEST_SESSION}:0.0" '#{pane_title}' 2>/dev/null)
if [ "$PANE_TITLE_00" = "$TEST_AGENT_1" ]; then
  expect.pass "pane title is $TEST_AGENT_1"
else
  expect.fail "pane title should be $TEST_AGENT_1, got: $PANE_TITLE_00"
fi

echo ""
echo "=== status/identity/fallback regression tests complete ==="
echo ""

# ============================================================================
# REGRESSION: status/team.status must NOT probe agents (no /status injection)
# Uses test session bash panes — safe, self-contained
# ============================================================================

TMUX_CMD="tmux -u"
# Test with our test session bash pane
STATUS_BASH_PANE="${TEST_SESSION}:0.2"
STATUS_BEFORE=$($TMUX_CMD capture-pane -t "$STATUS_BASH_PANE" -p 2>/dev/null | md5sum | cut -d' ' -f1)
hiveMind.team.status "$TEST_SESSION" 2>/dev/null > /dev/null
sleep 1
STATUS_AFTER=$($TMUX_CMD capture-pane -t "$STATUS_BASH_PANE" -p 2>/dev/null | md5sum | cut -d' ' -f1)
test.case $level "team.status does not modify bash panes" echo "$STATUS_BEFORE $STATUS_AFTER"
if [ "$STATUS_BEFORE" = "$STATUS_AFTER" ]; then
  expect.pass "bash pane unchanged after team.status"
else
  BASH_CAPTURE=$($TMUX_CMD capture-pane -t "$STATUS_BASH_PANE" -p -S -10 2>/dev/null)
  if echo "$BASH_CAPTURE" | grep -q "/status\|Status dialog"; then
    expect.fail "bash pane has /status injection after team.status"
  else
    expect.pass "pane changed but no /status injection"
  fi
fi

# --- consistency.audit still works ---
test.case $level "consistency.audit still runs" \
  hiveMind.consistency.audit
if [ "$RETURN_VALUE" -eq 0 ]; then
  expect.pass "consistency.audit completed"
else
  expect.fail "consistency.audit failed with rc=$RETURN_VALUE"
fi

# --- status output still shows UUIDs from non-invasive discovery ---
STATUS_TEXT=$(hiveMind.status 2>/dev/null)
test.case $level "status shows UUIDs" echo "$STATUS_TEXT"
# UUIDs look like [8hex] in the output
UUID_COUNT=$(echo "$STATUS_TEXT" | grep -oE '\[[0-9a-f]{8}\]' | wc -l | tr -d ' ')
if [ "$UUID_COUNT" -gt 0 ]; then
  expect.pass "status shows $UUID_COUNT UUIDs from non-invasive discovery"
else
  expect.fail "status shows no UUIDs — discovery broken"
fi

# --- status shows agent names (not just pane addresses) ---
test.case $level "status shows agent names" echo "$STATUS_TEXT"
if echo "$STATUS_TEXT" | grep -q "oosh-expert\|orchestrator\|scrum-master"; then
  expect.pass "status shows named agents"
else
  expect.fail "status missing agent names"
fi

echo ""
echo "=== non-invasive status regression tests complete ==="
echo ""

# ============================================================================
# REGRESSION: hiveMind.panes — flat agent list across all sessions
# Bug: old panes used hardcoded role grep, missed agents, showed bash shells
# Fix: uses claude.processes lookup, skips non-Claude panes, shows flat table
# ============================================================================

PANES_RAW=$(hiveMind.panes 2>/dev/null)
PANES_TEXT=$(echo "$PANES_RAW" | sed 's/\x1b\[[0-9;]*m//g')

# --- panes outputs a flat table (not tree) ---
test.case $level "panes shows flat table with PANE/ROLE/STATE/UUID header" echo "$PANES_TEXT"
if echo "$PANES_TEXT" | grep -q "^PANE.*ROLE.*STATE.*UUID"; then
  expect.pass "panes header present: PANE ROLE STATE UUID"
else
  expect.fail "panes missing flat table header"
fi

# --- panes shows agents from multiple sessions ---
test.case $level "panes includes agents from multiple sessions" echo "$PANES_TEXT"
SESSION_COUNT=$(echo "$PANES_TEXT" | grep -oP '^\S+(?=:)' | sort -u | wc -l | tr -d ' ')
if [ "$SESSION_COUNT" -ge 2 ]; then
  expect.pass "panes spans $SESSION_COUNT sessions"
else
  expect.fail "panes should span multiple sessions (got $SESSION_COUNT)"
fi

# --- panes does not show bash/offline panes ---
test.case $level "panes excludes bash shells and offline panes" echo "$PANES_TEXT"
# Data lines are those with session:window.pane format (skip header/separator/count)
BASH_LINES=$(echo "$PANES_TEXT" | grep -E '^\S+:\S+\.\S+' | grep -iE 'bash|offline' | wc -l | tr -d ' ')
if [ "$BASH_LINES" -eq 0 ]; then
  expect.pass "no bash/offline entries in panes output"
else
  expect.fail "panes should not show bash/offline ($BASH_LINES found)"
fi

# --- panes shows role names (not generic pane addresses) ---
test.case $level "panes shows named roles" echo "$PANES_TEXT"
if echo "$PANES_TEXT" | grep -qE 'orchestrator|oosh-expert|scrum-master|tester|product-owner|expert'; then
  expect.pass "panes shows named agent roles"
else
  expect.fail "panes should show named roles, not just pane addresses"
fi

# --- panes shows state for each agent ---
test.case $level "panes shows agent states" echo "$PANES_TEXT"
STATE_COUNT=$(echo "$PANES_TEXT" | grep -E '^\S+:\S+\.\S+' | grep -cE 'active|idle|accept-edits|stuck' | tr -d ' ')
if [ "$STATE_COUNT" -gt 0 ]; then
  expect.pass "panes shows $STATE_COUNT agents with state"
else
  expect.fail "panes should show agent states (active/idle/stuck/accept-edits)"
fi

# --- panes shows agent count at bottom ---
test.case $level "panes shows agent count" echo "$PANES_TEXT"
if echo "$PANES_TEXT" | grep -qE '[0-9]+ active agents'; then
  AGENT_COUNT=$(echo "$PANES_TEXT" | grep -oP '\d+(?= active agents)')
  expect.pass "panes reports $AGENT_COUNT active agents"
else
  expect.fail "panes should show 'N active agents' count"
fi

# --- panes count matches actual data lines ---
test.case $level "panes count matches table rows" echo "$PANES_TEXT"
TABLE_ROWS=$(echo "$PANES_TEXT" | grep -cE '^\S+:\S+\.\S+' | tr -d ' ')
REPORTED_COUNT=$(echo "$PANES_TEXT" | grep -oP '\d+(?= active agents)' || echo "0")
if [ "$TABLE_ROWS" -eq "$REPORTED_COUNT" ]; then
  expect.pass "count matches: $TABLE_ROWS rows, $REPORTED_COUNT reported"
else
  expect.fail "count mismatch: $TABLE_ROWS rows vs $REPORTED_COUNT reported"
fi

# --- panes does not probe agent panes (non-invasive) ---
TMUX_CMD="tmux -u"
PANES_TEST_PANE="upDownTeam:0.3"
PANES_BEFORE=$($TMUX_CMD capture-pane -t "$PANES_TEST_PANE" -p 2>/dev/null | md5sum | cut -d' ' -f1)
hiveMind.panes 2>/dev/null > /dev/null
sleep 2
PANES_AFTER=$($TMUX_CMD capture-pane -t "$PANES_TEST_PANE" -p 2>/dev/null | md5sum | cut -d' ' -f1)
test.case $level "panes does not inject into agent panes" echo "$PANES_BEFORE $PANES_AFTER"
if [ "$PANES_BEFORE" = "$PANES_AFTER" ]; then
  expect.pass "Claude pane unchanged after panes"
else
  if $TMUX_CMD capture-pane -t "$PANES_TEST_PANE" -p -S -5 2>/dev/null | grep -q "/status\|Status dialog"; then
    expect.fail "panes injected /status into $PANES_TEST_PANE"
  else
    expect.pass "pane changed but no /status injection (agent activity)"
  fi
fi

echo ""
echo "=== hiveMind.panes regression tests complete ==="
echo ""

# ============================================================================
# REGRESSION: hiveMind.list must match hiveMind.panes (same discovery)
# Bug: list only checked one session via pane titles; panes used claude.processes
# Fix: list uses identical non-invasive Claude process discovery as panes
# ============================================================================

# --- list returns agents ---
LIST_OUTPUT=$(hiveMind.list 2>/dev/null)
LIST_COUNT=$(echo "$LIST_OUTPUT" | grep -c . | tr -d ' ')
test.case $level "hiveMind.list returns agents" echo "$LIST_OUTPUT"
if [ "$LIST_COUNT" -gt 0 ]; then
  expect.pass "list returned $LIST_COUNT agents"
else
  expect.fail "list returned 0 agents"
fi

# --- panes agent count matches list count ---
PANES_RAW2=$(hiveMind.panes 2>/dev/null)
PANES_TEXT2=$(echo "$PANES_RAW2" | sed 's/\x1b\[[0-9;]*m//g')
PANES_COUNT2=$(echo "$PANES_TEXT2" | grep -oP '\d+(?= active agents)')
test.case $level "list count matches panes count" echo "list=$LIST_COUNT panes=$PANES_COUNT2"
if [ "$LIST_COUNT" -eq "$PANES_COUNT2" ]; then
  expect.pass "both report $LIST_COUNT agents"
else
  expect.fail "list=$LIST_COUNT vs panes=$PANES_COUNT2"
fi

# --- every agent in list appears in panes ---
LIST_SORTED=$(echo "$LIST_OUTPUT" | sort)
PANES_ROLES=$(echo "$PANES_TEXT2" | grep -E '^\S+:\S+\.\S+' | awk '{print $2}' | sort)
LIST_ONLY=$(comm -23 <(echo "$LIST_SORTED") <(echo "$PANES_ROLES"))
test.case $level "every list agent appears in panes" echo "list_only='$LIST_ONLY'"
if [ -z "$LIST_ONLY" ]; then
  expect.pass "all list agents found in panes"
else
  expect.fail "agents in list but not panes: $LIST_ONLY"
fi

# --- every agent in panes appears in list ---
PANES_ONLY=$(comm -13 <(echo "$LIST_SORTED") <(echo "$PANES_ROLES"))
test.case $level "every panes agent appears in list" echo "panes_only='$PANES_ONLY'"
if [ -z "$PANES_ONLY" ]; then
  expect.pass "all panes agents found in list"
else
  expect.fail "agents in panes but not list: $PANES_ONLY"
fi

# --- workers is a strict subset of list (no orchestrator/queen/product-owner) ---
WORKERS_OUTPUT=$(hiveMind.workers 2>/dev/null)
WORKERS_SORTED=$(echo "$WORKERS_OUTPUT" | sort)
WORKERS_COUNT=$(echo "$WORKERS_OUTPUT" | grep -c . | tr -d ' ')
test.case $level "workers is subset of list" echo "workers=$WORKERS_COUNT list=$LIST_COUNT"
WORKERS_EXTRA=$(comm -23 <(echo "$WORKERS_SORTED") <(echo "$LIST_SORTED"))
if [ -z "$WORKERS_EXTRA" ]; then
  expect.pass "all $WORKERS_COUNT workers found in list"
else
  expect.fail "workers not in list: $WORKERS_EXTRA"
fi

# --- workers excludes orchestrator and product-owner ---
test.case $level "workers excludes orchestrator/product-owner" echo "$WORKERS_OUTPUT"
if echo "$WORKERS_OUTPUT" | grep -qE "^(orchestrator|queen|product-owner)$"; then
  expect.fail "workers should not include orchestrator/queen/product-owner"
else
  expect.pass "workers correctly excludes leadership roles"
fi

# --- list uses non-invasive discovery (no pane probing) ---
TMUX_CMD="tmux -u"
LIST_TEST_PANE="upDownTeam:0.3"
LIST_BEFORE=$($TMUX_CMD capture-pane -t "$LIST_TEST_PANE" -p 2>/dev/null | md5sum | cut -d' ' -f1)
hiveMind.list 2>/dev/null > /dev/null
sleep 2
LIST_AFTER=$($TMUX_CMD capture-pane -t "$LIST_TEST_PANE" -p 2>/dev/null | md5sum | cut -d' ' -f1)
test.case $level "list does not inject into agent panes" echo "$LIST_BEFORE $LIST_AFTER"
if [ "$LIST_BEFORE" = "$LIST_AFTER" ]; then
  expect.pass "Claude pane unchanged after list"
else
  if $TMUX_CMD capture-pane -t "$LIST_TEST_PANE" -p -S -5 2>/dev/null | grep -q "/status\|Status dialog"; then
    expect.fail "list injected /status into $LIST_TEST_PANE"
  else
    expect.pass "pane changed but no /status injection (agent activity)"
  fi
fi

echo ""
echo "=== hiveMind.list/panes consistency regression tests complete ==="
echo ""

# ============================================================================
# REGRESSION: DRY — agents.discover must be the ONLY discovery entry point
# Bug: 6+ functions duplicated the claudeProcs+list.panes+registry pattern
# Fix: extracted hiveMind.protected.agents.discover; callers consume its output
# Guard: grep-based test fails if inline discovery patterns reappear
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"

# --- agents.discover function exists ---
test.case $level "hiveMind.protected.agents.discover exists" \
  type -t hiveMind.protected.agents.discover
if type -t hiveMind.protected.agents.discover &>/dev/null; then
  expect.pass "agents.discover function exists"
else
  expect.fail "agents.discover function missing"
fi

# --- agents.discover returns structured output ---
DISCOVER_OUT=$(hiveMind.protected.agents.discover 2>/dev/null)
DISCOVER_LINES=$(echo "$DISCOVER_OUT" | grep -c . | tr -d ' ')
test.case $level "agents.discover returns structured data" echo "$DISCOVER_LINES lines"
if [ "$DISCOVER_LINES" -gt 0 ]; then
  # Check format: pane|role|state|uuid|title|is_claude (6 pipe-separated fields)
  FIRST_LINE=$(echo "$DISCOVER_OUT" | head -1)
  FIELD_COUNT=$(echo "$FIRST_LINE" | awk -F'|' '{print NF}')
  if [ "$FIELD_COUNT" -eq 6 ]; then
    expect.pass "$DISCOVER_LINES lines, 6 fields per line"
  else
    expect.fail "expected 6 pipe fields, got $FIELD_COUNT: $FIRST_LINE"
  fi
else
  expect.fail "agents.discover returned 0 lines"
fi

# --- agents.discover output matches list and panes ---
DISCOVER_CLAUDE=$(echo "$DISCOVER_OUT" | awk -F'|' '$6=="yes"{print $2}' | sort)
LIST_SORTED2=$(hiveMind.list 2>/dev/null | sort)
test.case $level "agents.discover Claude agents match list" echo "discover=$(echo "$DISCOVER_CLAUDE" | wc -l | tr -d ' ') list=$(echo "$LIST_SORTED2" | wc -l | tr -d ' ')"
DISC_DIFF=$(diff <(echo "$DISCOVER_CLAUDE") <(echo "$LIST_SORTED2") 2>/dev/null)
if [ -z "$DISC_DIFF" ]; then
  expect.pass "discover and list return identical agent sets"
else
  expect.fail "mismatch: $DISC_DIFF"
fi

# --- callers of agents.discover (should be >= 3: list, panes, team.status) ---
CALLER_COUNT=$(grep -c 'private\.hiveMind\.agents\.discover' "$HIVEMIND_SRC" | tr -d ' ')
# Subtract 1 for the function definition itself
CALLER_COUNT=$((CALLER_COUNT - 1))
test.case $level "agents.discover has multiple callers" echo "$CALLER_COUNT callers"
if [ "$CALLER_COUNT" -ge 3 ]; then
  expect.pass "$CALLER_COUNT callers use shared discovery"
else
  expect.fail "only $CALLER_COUNT callers — expected >= 3"
fi

# --- ZERO inline claudeProcs patterns outside allowed functions ---
# Allowed: agents.discover (the shared method), consistency.audit, consistency.fix
# (audit/fix iterate ALL panes including non-Claude for full cross-comparison)
# Any new 'local -A claudeProcs' means someone duplicated the pattern.
TOTAL_CLAUDEPROCS=$(grep -c 'local -A claudeProcs' "$HIVEMIND_SRC" | tr -d ' ')
# Allowed budget: agents.discover(1) + consistency.audit(1) + consistency.fix(1) = 3 max
ALLOWED_MAX=3
test.case $level "claudeProcs array declarations within budget" echo "total=$TOTAL_CLAUDEPROCS allowed=$ALLOWED_MAX"
if [ "$TOTAL_CLAUDEPROCS" -le "$ALLOWED_MAX" ]; then
  expect.pass "$TOTAL_CLAUDEPROCS claudeProcs declarations (budget=$ALLOWED_MAX)"
else
  LOCATIONS=$(grep -n 'local -A claudeProcs' "$HIVEMIND_SRC")
  expect.fail "$TOTAL_CLAUDEPROCS exceeds budget $ALLOWED_MAX: $LOCATIONS"
fi

# --- claude.processes calls within budget ---
# Allowed: agents.discover(1) + claude.processes definition(1) + consistency.audit(1)
#          + consistency.fix(1) + process.list(1) + teams.save(1)
#          + session.resolve.uuid livePanes filter(1) = 7 max
# The 7th (session.resolve.uuid) is an architectural necessity — it needs the
# live-pane set to disambiguate fork UUIDs from stale cross-pane assignments.
TOTAL_PROC_CALLS=$(grep -c 'private\.hiveMind\.claude\.processes' "$HIVEMIND_SRC" | tr -d ' ')
PROC_BUDGET=7
test.case $level "claude.processes calls within budget" echo "total=$TOTAL_PROC_CALLS budget=$PROC_BUDGET"
if [ "$TOTAL_PROC_CALLS" -le "$PROC_BUDGET" ]; then
  expect.pass "$TOTAL_PROC_CALLS claude.processes refs (budget=$PROC_BUDGET)"
else
  LOCATIONS=$(grep -n 'private\.hiveMind\.claude\.processes' "$HIVEMIND_SRC")
  expect.fail "$TOTAL_PROC_CALLS exceeds budget $PROC_BUDGET: $LOCATIONS"
fi

echo ""
echo "=== DRY discovery regression tests complete ==="
echo ""

# --- HIVEMIND_AGENTS_DIR must not be set in test.hiveMind ---
# It is set once in hiveMind.start() — tests must not duplicate it
# Use grep -v 'grep\|SETS=' to exclude this test's own grep lines
TEST_SRC="$OOSH_DIR/test/test.hiveMind"
AGENTS_DIR_SETS=$(grep 'HIVEMIND_AGENTS_DIR=' "$TEST_SRC" | grep -v 'grep\|SETS=\|LOCS=' | grep -c . | tr -d ' ')
test.case $level "HIVEMIND_AGENTS_DIR not set in test file" echo "assignments=$AGENTS_DIR_SETS"
if [ "$AGENTS_DIR_SETS" -eq 0 ]; then
  expect.pass "zero HIVEMIND_AGENTS_DIR assignments in test.hiveMind"
else
  LOCS=$(grep -n 'HIVEMIND_AGENTS_DIR=' "$TEST_SRC" | grep -v 'grep\|SETS=\|LOCS=')
  expect.fail "$AGENTS_DIR_SETS assignments found: $LOCS"
fi

echo ""
echo "=== DRY HIVEMIND_AGENTS_DIR regression test complete ==="
echo ""

# ============================================================================
# REGRESSION: Registry invariants — live agents must never lose registry
# Rule: as long as a Claude session has a UUID and is alive, its registry
# entry MUST NOT be removed. The registry is the fallback for restoring
# dropped tmux sessions. Live tmux is master for updating registry.
# ============================================================================

# --- every live Claude agent has a registry entry ---
LIVE_AGENTS=$(hiveMind.list 2>/dev/null)
LIVE_COUNT=$(echo "$LIVE_AGENTS" | grep -c . | tr -d ' ')
REG_ROLES=$(cat "$REG_FILE" 2>/dev/null | cut -d'|' -f2 | sort)
MISSING_REG=""
while IFS= read -r agent; do
  [ -z "$agent" ] && continue
  if ! echo "$REG_ROLES" | grep -qx "$agent"; then
    MISSING_REG="${MISSING_REG} $agent"
  fi
done <<< "$LIVE_AGENTS"
test.case $level "every live agent has registry entry" echo "live=$LIVE_COUNT missing='$MISSING_REG'"
if [ -z "$MISSING_REG" ]; then
  expect.pass "all $LIVE_COUNT live agents have registry entries"
else
  expect.fail "live agents missing from registry:$MISSING_REG"
fi

# --- registry entries point to valid tmux panes ---
REG_PANES=$(cat "$REG_FILE" 2>/dev/null | cut -d'|' -f1)
STALE_PANES=""
STALE_COUNT=0
while IFS= read -r pane; do
  [ -z "$pane" ] && continue
  if ! otmux has "${pane%%:*}" 2>/dev/null; then
    STALE_PANES="${STALE_PANES} $pane"
    STALE_COUNT=$((STALE_COUNT + 1))
  fi
done <<< "$REG_PANES"
test.case $level "registry panes point to valid sessions" echo "stale=$STALE_COUNT"
if [ "$STALE_COUNT" -eq 0 ]; then
  expect.pass "all registry panes have valid tmux sessions"
else
  # Stale entries are allowed IF session was dropped — they enable restore
  expect.pass "registry has $STALE_COUNT entries for dropped sessions (restore fallback)"
fi

# --- consistency.fix must NOT remove entries for live agents ---
# Snapshot registry, run consistency.fix, verify live entries survive
REG_BEFORE=$(cat "$REG_FILE" 2>/dev/null | sort)
hiveMind.consistency.fix 2>/dev/null
REG_AFTER=$(cat "$REG_FILE" 2>/dev/null | sort)
REMOVED=$(comm -23 <(echo "$REG_BEFORE") <(echo "$REG_AFTER"))
test.case $level "consistency.fix preserves live agent entries" echo "removed='$REMOVED'"
if [ -z "$REMOVED" ]; then
  expect.pass "no registry entries removed by consistency.fix"
else
  # Check if removed entries were for live agents
  REMOVED_LIVE=""
  while IFS='|' read -r pane role; do
    [ -z "$pane" ] && continue
    if echo "$LIVE_AGENTS" | grep -qx "$role"; then
      REMOVED_LIVE="${REMOVED_LIVE} $role"
    fi
  done <<< "$REMOVED"
  if [ -z "$REMOVED_LIVE" ]; then
    expect.pass "removed entries were stale (not live agents)"
  else
    expect.fail "consistency.fix removed LIVE agents:$REMOVED_LIVE"
  fi
fi

# --- hiveMind panes shows full UUIDs (not truncated 8-char) ---
PANES_OUT=$(hiveMind.panes 2>/dev/null | sed 's/\x1b\[[0-9;]*m//g')
# Extract UUID column — full UUIDs are 36 chars (8-4-4-4-12), truncated are 8
UUID_LINES=$(echo "$PANES_OUT" | grep -oE '[0-9a-f-]{8,}' | grep -v '^-$')
SHORT_UUIDS=$(echo "$UUID_LINES" | awk 'length < 36 && length > 0' | head -5)
SHORT_COUNT=$(echo "$SHORT_UUIDS" | grep -c . | tr -d ' ')
test.case $level "panes shows full UUIDs (not truncated)" echo "short=$SHORT_COUNT"
if [ "$SHORT_COUNT" -eq 0 ]; then
  expect.pass "all UUIDs are full length"
else
  expect.fail "$SHORT_COUNT truncated UUIDs found: $SHORT_UUIDS"
fi

# --- hiveMind status shows full UUIDs ---
STATUS_OUT=$(hiveMind.status 2>/dev/null | sed 's/\x1b\[[0-9;]*m//g')
STATUS_UUIDS=$(echo "$STATUS_OUT" | grep -oE '\[[0-9a-f-]+\]' | tr -d '[]')
STATUS_SHORT=$(echo "$STATUS_UUIDS" | awk 'length < 36 && length > 0' | head -5)
STATUS_SHORT_COUNT=$(echo "$STATUS_SHORT" | grep -c . | tr -d ' ')
test.case $level "status shows full UUIDs (not truncated)" echo "short=$STATUS_SHORT_COUNT"
if [ "$STATUS_SHORT_COUNT" -eq 0 ]; then
  expect.pass "all status UUIDs are full length"
else
  expect.fail "$STATUS_SHORT_COUNT truncated UUIDs in status: $STATUS_SHORT"
fi

# --- parameter names in method signatures use <agentName> consistently ---
HIVEMIND_SRC="$OOSH_DIR/hiveMind"
# Count methods using old inconsistent names: <name>, <role>, <agentId>, <agent>
# that should be <agentName>. Exclude private helpers and completion functions.
OLD_PARAMS=$(grep -n '# <name>\|# <role>\|# <agentId>\|# <agent>' "$HIVEMIND_SRC" | grep -v 'private\.\|completion\.\|<agentName>\|<roleName>\|<host>\|<pane>' | grep -v '# <role>.*roleName\|# list\|# set\|# get')
OLD_COUNT=$(echo "$OLD_PARAMS" | grep -c . | tr -d ' ')
test.case $level "method signatures use consistent parameter names" echo "old_style=$OLD_COUNT"
if [ "$OLD_COUNT" -eq 0 ]; then
  expect.pass "all public methods use <agentName>"
else
  expect.fail "$OLD_COUNT methods use inconsistent param names"
fi

echo ""
echo "=== registry invariant + UUID + param naming tests complete ==="
echo ""

# ============================================================================
# REGRESSION: UUID integrity — code-level + live measurement
# Bug: UUID truncation (8-char) throughout; agents sharing other sessions
# ============================================================================

# --- CODE-LEVEL: hiveMind must never truncate UUIDs in display ---
# Check that no display function uses ${uuid:0:8} or uuidShort patterns
HIVEMIND_SRC="$OOSH_DIR/hiveMind"
UUID_TRUNC_PATTERNS=$(grep -n 'uuidShort\|uuid:0:8\|sid:0:8\|{uuid%%-*}' "$HIVEMIND_SRC" | grep -v '^\s*#' | head -10)
UUID_TRUNC_PAT_COUNT=$(echo "$UUID_TRUNC_PATTERNS" | grep -c . | tr -d ' ')
test.case $level "no UUID truncation patterns in hiveMind code" echo "patterns=$UUID_TRUNC_PAT_COUNT"
if [ "$UUID_TRUNC_PAT_COUNT" -eq 0 ]; then
  expect.pass "zero UUID truncation patterns in source"
else
  expect.fail "$UUID_TRUNC_PAT_COUNT truncation patterns: $UUID_TRUNC_PATTERNS"
fi

# --- CODE-LEVEL: process.list must not use sidShort or truncated display ---
PROC_LIST_FUNC=$(sed -n '/hiveMind\.process\.list()/,/^}/p' "$HIVEMIND_SRC")
PROC_TRUNC_CODE=$(echo "$PROC_LIST_FUNC" | grep -E 'sidShort|:0:8|Short' | head -5)
PROC_TRUNC_CODE_COUNT=$(echo "$PROC_TRUNC_CODE" | grep -c . | tr -d ' ')
test.case $level "process.list code has no UUID truncation" echo "truncation_lines=$PROC_TRUNC_CODE_COUNT"
if [ "$PROC_TRUNC_CODE_COUNT" -eq 0 ]; then
  expect.pass "process.list shows full UUIDs in code"
else
  expect.fail "process.list still truncates: $PROC_TRUNC_CODE"
fi

# --- LIVE: if agents exist, verify UUID uniqueness ---
if [ -n "$LIVE_SESSION" ]; then
  DISCOVER_DATA=$(hiveMind.protected.agents.discover 2>/dev/null)
  CLAUDE_UUIDS=""
  while IFS='|' read -r pane role state uuid title is_claude; do
    [ "$is_claude" != "yes" ] && continue
    [ -z "$uuid" ] && continue
    CLAUDE_UUIDS="${CLAUDE_UUIDS}${pane}|${role}|${uuid}"$'\n'
  done <<< "$DISCOVER_DATA"

  # Each UUID must map to exactly ONE pane
  DUP_REPORT=""
  DUP_COUNT=0
  declare -A UUID_PANES
  while IFS='|' read -r pane role uuid; do
    [ -z "$uuid" ] && continue
    if [ -n "${UUID_PANES[$uuid]:-}" ]; then
      UUID_PANES[$uuid]="${UUID_PANES[$uuid]}, ${role}@${pane}"
      DUP_COUNT=$((DUP_COUNT + 1))
    else
      UUID_PANES[$uuid]="${role}@${pane}"
    fi
  done <<< "$CLAUDE_UUIDS"
  for uuid in "${!UUID_PANES[@]}"; do
    count=$(echo "${UUID_PANES[$uuid]}" | tr ',' '\n' | grep -c . | tr -d ' ')
    if [ "$count" -gt 1 ]; then
      DUP_REPORT="${DUP_REPORT}  ${uuid:0:8}: ${UUID_PANES[$uuid]}"$'\n'
    fi
  done
  test.case $level "each UUID maps to exactly one pane" echo "duplicates=$DUP_COUNT"
  if [ "$DUP_COUNT" -eq 0 ]; then
    expect.pass "all UUIDs are unique per pane"
  else
    expect.fail "$DUP_COUNT duplicate UUID assignments: $DUP_REPORT"
  fi
  unset UUID_PANES

  # process.list must show role for every Claude agent
  PROC_OUT=$(hiveMind.process.list 2>/dev/null | sed 's/\x1b\[[0-9;]*m//g')
  PROC_NO_ROLE=$(echo "$PROC_OUT" | grep -E '^\s*[0-9]+' | awk '{print $3}' | grep -x '-' | head -5)
  PROC_NO_ROLE_COUNT=$(echo "$PROC_NO_ROLE" | grep -c . | tr -d ' ')
  test.case $level "process.list shows role for every agent" echo "no_role=$PROC_NO_ROLE_COUNT"
  if [ "$PROC_NO_ROLE_COUNT" -eq 0 ]; then
    expect.pass "all processes have roles"
  else
    expect.fail "$PROC_NO_ROLE_COUNT processes without role"
  fi

  # panes UUIDs match discover UUIDs
  PANES_DATA=$(hiveMind.panes 2>/dev/null | sed 's/\x1b\[[0-9;]*m//g')
  MISMATCH=""
  while IFS='|' read -r pane role state uuid title is_claude; do
    [ "$is_claude" != "yes" ] && continue
    [ -z "$uuid" ] && continue
    PANE_LINE=$(echo "$PANES_DATA" | grep "^${pane} ")
    if [ -n "$PANE_LINE" ]; then
      PANE_UUID=$(echo "$PANE_LINE" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
      if [ "$PANE_UUID" != "$uuid" ]; then
        MISMATCH="${MISMATCH}  ${pane}: discover=${uuid:0:8} panes=${PANE_UUID:0:8}"$'\n'
      fi
    fi
  done <<< "$DISCOVER_DATA"
  MISMATCH_COUNT=0
  [ -n "$MISMATCH" ] && MISMATCH_COUNT=$(echo "$MISMATCH" | grep -c . | tr -d ' ')
  test.case $level "panes UUIDs match discover UUIDs" echo "mismatches=$MISMATCH_COUNT"
  if [ "$MISMATCH_COUNT" -eq 0 ]; then
    expect.pass "all UUIDs consistent between panes and discover"
  else
    expect.fail "$MISMATCH_COUNT UUID mismatches: $MISMATCH"
  fi
else
  test.case $level "UUID uniqueness (skipped — no live agents)" echo "LIVE_SESSION empty"
  expect.pass "skipped — no live agents to measure"
  test.case $level "process.list roles (skipped — no live agents)" echo "LIVE_SESSION empty"
  expect.pass "skipped — no live agents"
  test.case $level "panes/discover consistency (skipped — no live agents)" echo "LIVE_SESSION empty"
  expect.pass "skipped — no live agents"
fi

echo ""
echo "=== UUID integrity tests complete ==="
echo ""

# ============================================================================
# REGRESSION: UUID consistency across all 3 sources
# Bug: sessions.env, process args, and JSONL files return different UUIDs
# Rule: for each live agent, all sources must agree on the UUID
# Sources: sessions.env (pane→UUID), process args (ps -p PID), JSONL on disk
# ============================================================================

if [ -n "$LIVE_SESSION" ]; then
  SESS_ENV="${CONFIG_PATH:-$HOME/config}/hivemind.sessions.env"
  ROLES_ENV="${CONFIG_PATH:-$HOME/config}/hivemind.roles.env"
  UUID_MISMATCH=""
  UUID_MISMATCH_COUNT=0
  UUID_CHECKED=0

  while IFS='|' read -r pane role; do
    [ -z "$pane" ] || [ -z "$role" ] && continue

    # Source 1: sessions.env UUID
    sess_uuid=""
    [ -f "$SESS_ENV" ] && sess_uuid=$(grep "^${pane}|" "$SESS_ENV" 2>/dev/null | tail -1 | cut -d'|' -f2)

    # Source 2: process args UUID (what hiveMind currently uses)
    proc_uuid=""
    pid=""
    pid=$(claudeCode.process.find "$pane" 2>/dev/null || true)
    if [ -n "$pid" ]; then
      proc_uuid=$(ps -p "$pid" -o args= 2>/dev/null | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -1)
    fi

    # Skip if no Claude process
    [ -z "$proc_uuid" ] && [ -z "$sess_uuid" ] && continue
    UUID_CHECKED=$((UUID_CHECKED + 1))

    # Compare: sessions.env should match process args
    if [ -n "$sess_uuid" ] && [ -n "$proc_uuid" ] && [ "$sess_uuid" != "$proc_uuid" ]; then
      UUID_MISMATCH="${UUID_MISMATCH}  ${role}@${pane}: sessions.env=${sess_uuid:0:8} process=${proc_uuid:0:8}"$'\n'
      UUID_MISMATCH_COUNT=$((UUID_MISMATCH_COUNT + 1))
    fi
  done < "$ROLES_ENV"

  test.case $level "sessions.env and process args UUIDs agree" echo "checked=$UUID_CHECKED mismatches=$UUID_MISMATCH_COUNT"
  if [ "$UUID_MISMATCH_COUNT" -eq 0 ]; then
    expect.pass "all $UUID_CHECKED agents: sessions.env matches process args"
  else
    expect.fail "$UUID_MISMATCH_COUNT mismatches: $UUID_MISMATCH"
  fi

  # --- claudeCode session.id must return same UUID as sessions.env ---
  CC_MISMATCH=""
  CC_MISMATCH_COUNT=0
  CC_CHECKED=0
  while IFS='|' read -r pane role; do
    [ -z "$pane" ] || [ -z "$role" ] && continue
    sess_uuid=""
    [ -f "$SESS_ENV" ] && sess_uuid=$(grep "^${pane}|" "$SESS_ENV" 2>/dev/null | tail -1 | cut -d'|' -f2)
    [ -z "$sess_uuid" ] && continue

    cc_uuid=""
    cc_uuid=$(claudeCode.session.id "$pane" 2>/dev/null || true)
    [ -z "$cc_uuid" ] && continue
    CC_CHECKED=$((CC_CHECKED + 1))

    if [ "$cc_uuid" != "$sess_uuid" ]; then
      CC_MISMATCH="${CC_MISMATCH}  ${role}@${pane}: session.id=${cc_uuid:0:8} sessions.env=${sess_uuid:0:8}"$'\n'
      CC_MISMATCH_COUNT=$((CC_MISMATCH_COUNT + 1))
    fi
  done < "$ROLES_ENV"

  test.case $level "claudeCode session.id matches sessions.env" echo "checked=$CC_CHECKED mismatches=$CC_MISMATCH_COUNT"
  if [ "$CC_MISMATCH_COUNT" -eq 0 ]; then
    expect.pass "all $CC_CHECKED agents: session.id agrees with sessions.env"
  else
    expect.fail "$CC_MISMATCH_COUNT mismatches: $CC_MISMATCH"
  fi

  # --- hiveMind panes UUID must match sessions.env ---
  PANES_DATA2=$(hiveMind.panes 2>/dev/null | sed 's/\x1b\[[0-9;]*m//g')
  PANES_MISMATCH=""
  PANES_MISMATCH_COUNT=0
  while IFS='|' read -r pane role; do
    [ -z "$pane" ] || [ -z "$role" ] && continue
    sess_uuid=""
    [ -f "$SESS_ENV" ] && sess_uuid=$(grep "^${pane}|" "$SESS_ENV" 2>/dev/null | tail -1 | cut -d'|' -f2)
    [ -z "$sess_uuid" ] && continue

    panes_uuid=""
    panes_uuid=$(echo "$PANES_DATA2" | grep "^${pane} " | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
    [ -z "$panes_uuid" ] && continue

    if [ "$panes_uuid" != "$sess_uuid" ]; then
      PANES_MISMATCH="${PANES_MISMATCH}  ${role}@${pane}: panes=${panes_uuid:0:8} sessions.env=${sess_uuid:0:8}"$'\n'
      PANES_MISMATCH_COUNT=$((PANES_MISMATCH_COUNT + 1))
    fi
  done < "$ROLES_ENV"

  test.case $level "hiveMind panes UUID matches sessions.env" echo "mismatches=$PANES_MISMATCH_COUNT"
  if [ "$PANES_MISMATCH_COUNT" -eq 0 ]; then
    expect.pass "panes UUIDs agree with sessions.env"
  else
    expect.fail "$PANES_MISMATCH_COUNT mismatches: $PANES_MISMATCH"
  fi
else
  test.case $level "UUID cross-source consistency (skipped — no live agents)" echo "skip"
  expect.pass "skipped — no live agents"
  test.case $level "session.id consistency (skipped)" echo "skip"
  expect.pass "skipped"
  test.case $level "panes UUID consistency (skipped)" echo "skip"
  expect.pass "skipped"
fi

echo ""
echo "=== UUID cross-source consistency tests complete ==="
echo ""

# ============================================================================
# BUG: hiveMind resolve must find agents across ALL teams, not just active
# Bug: resolve scopes to active team only — agents in other teams not found
# agent.monitor fails for cross-team agents (e.g. web4-tester in upDownTeam)
# ============================================================================

# Self-contained: create 2 test teams with agents, set one as active,
# verify resolve finds agents from BOTH teams.
if otmux sessions >/dev/null 2>&1; then

  XTEAM_A="__test_xteam_a_$$"
  XTEAM_B="__test_xteam_b_$$"

  # Create 2 test sessions
  otmux new "$XTEAM_A" -d 2>/dev/null
  otmux new "$XTEAM_B" -d 2>/dev/null

  # Register roles in different teams
  private.hiveMind.registry.set "${XTEAM_A}:0.0" "xteam-alpha"
  private.hiveMind.registry.set "${XTEAM_B}:0.0" "xteam-beta"

  # Set team A as active
  echo "$XTEAM_A" > "${CONFIG_PATH:-$HOME/config}/hivemind.active.team"

  # --- T-RESOLVE-CROSS-1: resolve finds agent in active team ---
  test.case $level "T-RESOLVE-CROSS-1: resolve finds agent in active team" \
    hiveMind.resolve "xteam-alpha" "$XTEAM_A"
  RESOLVE_A=$(hiveMind.resolve "xteam-alpha" "$XTEAM_A" 2>/dev/null)
  if [ "$RESOLVE_A" = "${XTEAM_A}:0.0" ]; then
    expect.pass "found xteam-alpha in active team: $RESOLVE_A"
  else
    expect.fail "expected ${XTEAM_A}:0.0, got: $RESOLVE_A"
  fi

  # --- T-RESOLVE-CROSS-2: resolve finds agent in OTHER team without session arg ---
  test.case $level "T-RESOLVE-CROSS-2: resolve finds agent across all teams" \
    echo "resolving xteam-beta without session"
  RESOLVE_B=$(hiveMind.resolve "xteam-beta" 2>/dev/null)
  if [ "$RESOLVE_B" = "${XTEAM_B}:0.0" ]; then
    expect.pass "found xteam-beta cross-team: $RESOLVE_B"
  else
    expect.fail "resolve should find xteam-beta in ${XTEAM_B}:0.0 but got: '$RESOLVE_B'"
  fi

  # --- T-RESOLVE-CROSS-3: resolve with no session falls back to registry search ---
  test.case $level "T-RESOLVE-CROSS-3: resolve fallback searches full registry" \
    echo "testing registry fallback"
  # xteam-beta is NOT in active team, only in registry for XTEAM_B
  RESOLVE_FALLBACK=$(hiveMind.resolve "xteam-beta" 2>/dev/null)
  if [ -n "$RESOLVE_FALLBACK" ]; then
    expect.pass "registry fallback found: $RESOLVE_FALLBACK"
  else
    expect.fail "resolve should fall back to full registry search when not in active team"
  fi

  # --- T-RESOLVE-CROSS-4: agent.monitor works cross-team ---
  test.case $level "T-RESOLVE-CROSS-4: agent.monitor works for cross-team agent" \
    echo "testing agent.monitor cross-team"
  if type -t hiveMind.agent.monitor &>/dev/null; then
    MONITOR_OUT=$(hiveMind.agent.monitor "xteam-beta" 2 2>/dev/null)
    MONITOR_RC=$?
    if [ "$MONITOR_RC" -eq 0 ]; then
      expect.pass "agent.monitor found xteam-beta cross-team"
    else
      expect.fail "agent.monitor should work cross-team (rc=$MONITOR_RC)"
    fi
  else
    expect.pass "skipped — agent.monitor not defined"
  fi

  # Cleanup
  otmux kill "$XTEAM_A" 2>/dev/null
  otmux kill "$XTEAM_B" 2>/dev/null
  [ -f "$REG_FILE" ] && grep -v '__test_xteam_' "$REG_FILE" > "${REG_FILE}.xclean" 2>/dev/null && mv "${REG_FILE}.xclean" "$REG_FILE"
  # Restore active team
  echo "$TEST_SESSION" > "${CONFIG_PATH:-$HOME/config}/hivemind.active.team" 2>/dev/null

else
  test.case $level "T-RESOLVE-CROSS-1: resolve active team (skipped — no tmux)" echo "skip"
  expect.pass "skipped"
  test.case $level "T-RESOLVE-CROSS-2: resolve cross-team (skipped)" echo "skip"
  expect.pass "skipped"
  test.case $level "T-RESOLVE-CROSS-3: registry fallback (skipped)" echo "skip"
  expect.pass "skipped"
  test.case $level "T-RESOLVE-CROSS-4: agent.monitor cross-team (skipped)" echo "skip"
  expect.pass "skipped"
fi

echo ""
echo "=== cross-team resolve tests complete ==="
echo ""

# ============================================================================
# FEATURE: hiveMind team.pull + agent.restart (remote offloading)
# TDD: tests written BEFORE implementation — expert will make them pass
# ============================================================================

# --- Shared setup for pull/restart tests ---
TEST_PULL_HOST="mock-remote-$$"
TEST_PULL_DIR="${TMPDIR:-/tmp}/hivemind.${TEST_PULL_HOST}"
TEST_ARESTART_SESS="__test_arestart_$$"

# Mock SSH config
TEST_SSH_DIR=$(mktemp -d "${TMPDIR:-/tmp}/__test_sshdir_$$.XXXXXX")
cat > "$TEST_SSH_DIR/config" <<SSHEOF
Host mock-remote-$$
  HostName 192.168.99.99
Host mock-gateway-$$
  HostName 10.0.0.1
SSHEOF
ORIG_SSH_DIR="${CURRENT_SSH_DIR:-}"
export CURRENT_SSH_DIR="$TEST_SSH_DIR"

# ── A. team.pull tests ──────────────────────────────────────────────────────

test.case $level "T-PULL-1: team.pull function exists" \
  type -t hiveMind.team.pull
if type -t hiveMind.team.pull &>/dev/null; then
  expect.pass "hiveMind.team.pull function exists"
else
  expect.fail "hiveMind.team.pull should be defined"
fi

test.case $level "T-PULL-2: team.pull completion returns SSH hosts" \
  type -t hiveMind.team.pull.completion.host
if type -t hiveMind.team.pull.completion.host &>/dev/null; then
  PULL_HOSTS=$(hiveMind.team.pull.completion.host 2>/dev/null)
  if echo "$PULL_HOSTS" | grep -q "mock-remote-$$"; then
    expect.pass "completion returns mock SSH host"
  else
    expect.fail "completion should return mock-remote-$$ from SSH config"
  fi
else
  expect.fail "hiveMind.team.pull.completion.host should be defined"
fi

test.case $level "T-PULL-3: team.pull with no args returns error" \
  hiveMind.team.pull
if [ "$RETURN_VALUE" -ne 0 ]; then
  expect.pass "team.pull rejects missing host arg"
else
  expect.fail "team.pull should return non-zero without args"
fi

test.case $level "T-PULL-4: team.pull with bad host returns error" \
  echo "testing unreachable host"
if type -t hiveMind.team.pull &>/dev/null; then
  timeout 15 hiveMind.team.pull "nonexistent-host-$$" 2>/dev/null
  PULL_RC=$?
  if [ "$PULL_RC" -ne 0 ]; then
    expect.pass "team.pull fails for unreachable host (rc=$PULL_RC)"
  else
    expect.fail "team.pull should fail for unreachable host"
  fi
  rm -rf "${TMPDIR:-/tmp}/hivemind.nonexistent-host-$$" 2>/dev/null
else
  expect.pass "skipped — team.pull not yet implemented"
fi

# T-PULL-5..7: Validate pulled directory structure
# Create fixture simulating what team.pull would produce
PULL_FIXTURE="${TMPDIR:-/tmp}/hivemind.__test_pull_$$"
mkdir -p "$PULL_FIXTURE"
cat > "$PULL_FIXTURE/hivemind.snapshot.env" <<SNAPEOF
# hiveMind snapshot test-pull
# session|address|role|uuid|title
remoteTeam|0.0|remote-orchestrator|aaaa1111-2222-3333-4444-555566667777|remote-orchestrator
remoteTeam|0.1|remote-coder|bbbb1111-2222-3333-4444-555566667777|remote-coder
remoteTeam|0.2|remote-tester||remote-tester
SNAPEOF
cat > "$PULL_FIXTURE/hivemind.roles.env" <<ROLESEOF
remoteTeam:0.0|remote-orchestrator
remoteTeam:0.1|remote-coder
remoteTeam:0.2|remote-tester
ROLESEOF
cat > "$PULL_FIXTURE/hivemind.sessions.env" <<SESSEOF
remoteTeam:0.0|aaaa1111-2222-3333-4444-555566667777
remoteTeam:0.1|bbbb1111-2222-3333-4444-555566667777
SESSEOF
echo '{"type":"custom-title","customTitle":"remote-coder","sessionId":"bbbb1111-2222-3333-4444-555566667777"}' > "$PULL_FIXTURE/bbbb1111-2222-3333-4444-555566667777.jsonl"

test.case $level "T-PULL-5: pulled directory has snapshot + roles + sessions" \
  echo "checking $PULL_FIXTURE"
if [ -f "$PULL_FIXTURE/hivemind.snapshot.env" ] && \
   [ -f "$PULL_FIXTURE/hivemind.roles.env" ] && \
   [ -f "$PULL_FIXTURE/hivemind.sessions.env" ]; then
  expect.pass "fixture directory has all required config files"
else
  expect.fail "pulled directory missing required files"
fi

test.case $level "T-PULL-6: snapshot has correct format" \
  echo "checking snapshot format"
SNAP_HEADER=$(head -1 "$PULL_FIXTURE/hivemind.snapshot.env")
SNAP_FIELDS=$(grep -v '^#' "$PULL_FIXTURE/hivemind.snapshot.env" | head -1 | awk -F'|' '{print NF}')
if echo "$SNAP_HEADER" | grep -q "^# hiveMind snapshot" && [ "$SNAP_FIELDS" -eq 5 ]; then
  expect.pass "snapshot: correct header + 5-field records"
else
  expect.fail "snapshot format wrong: header='$SNAP_HEADER' fields=$SNAP_FIELDS"
fi

test.case $level "T-PULL-7: JSONL files present for agents with UUIDs" \
  echo "checking JONLs"
PULL_JSONL_COUNT=$(ls "$PULL_FIXTURE"/*.jsonl 2>/dev/null | wc -l | tr -d ' ')
if [ "$PULL_JSONL_COUNT" -ge 1 ]; then
  expect.pass "$PULL_JSONL_COUNT JSONL files in pulled directory"
else
  expect.fail "pulled directory should contain JSONL session files"
fi

# --- T-PULL-8: JSONL download loop must not consume stdin ---
# Bug: while-read loop uses bare 'done < file'; ossh exec/scp inside
# consumes stdin, eating remaining snapshot lines. Only 1st UUID downloaded.
# Test: grep-based code pattern check only (no execution — avoids triggering the bug)
HIVEMIND_SRC="$OOSH_DIR/hiveMind"

# Count while-read loops that read snapshot via bare stdin (vulnerable)
BARE_STDIN_LOOPS=$(grep -c 'done < .*snapshot' "$HIVEMIND_SRC" | tr -d ' ')
# Count loops using fd 3 redirect (fixed)
FD3_LOOPS=$(grep -c '<&3\|done 3<' "$HIVEMIND_SRC" | tr -d ' ')
# Count ossh/ssh/scp calls with < /dev/null (also fixed)
DEVNULL_CMDS=$(grep -c 'ossh.*< /dev/null\|scp.*< /dev/null\|ssh.*< /dev/null' "$HIVEMIND_SRC" | tr -d ' ')

test.case $level "T-PULL-8: snapshot loops protected from stdin consumption" \
  echo "bare_stdin=$BARE_STDIN_LOOPS fd3=$FD3_LOOPS devnull=$DEVNULL_CMDS"
if [ "$BARE_STDIN_LOOPS" -eq 0 ]; then
  expect.pass "zero bare stdin snapshot loops (all use fd 3 or < /dev/null)"
elif [ "$FD3_LOOPS" -gt 0 ] || [ "$DEVNULL_CMDS" -gt 0 ]; then
  expect.pass "snapshot loops use fd3=$FD3_LOOPS devnull=$DEVNULL_CMDS (protected)"
else
  expect.fail "$BARE_STDIN_LOOPS bare stdin loops with no fd3 or devnull protection — bug present"
fi

echo ""
echo "=== team.pull tests complete ==="
echo ""

# ── B. agent.restart (single-role) tests ────────────────────────────────────
# d94e9cc: agent.restart now takes <configDir> <role> for single-agent restart
# Old all-agents behavior moved to team.restart

test.case $level "T-ARESTART-1: agent.restart function exists" \
  type -t hiveMind.agent.restart
if type -t hiveMind.agent.restart &>/dev/null; then
  expect.pass "hiveMind.agent.restart function exists"
else
  expect.fail "hiveMind.agent.restart should be defined"
fi

test.case $level "T-ARESTART-2: agent.restart.completion.configDir returns hivemind.* dirs" \
  type -t hiveMind.agent.restart.completion.configDir
if type -t hiveMind.agent.restart.completion.configDir &>/dev/null; then
  mkdir -p "${TMPDIR:-/tmp}/hivemind.__test_comp_$$"
  RESTART_DIRS=$(hiveMind.agent.restart.completion.configDir 2>/dev/null)
  rm -rf "${TMPDIR:-/tmp}/hivemind.__test_comp_$$"
  if echo "$RESTART_DIRS" | grep -q "hivemind\."; then
    expect.pass "completion returns hivemind.* directories"
  else
    expect.fail "completion should list hivemind.* directories"
  fi
else
  expect.fail "hiveMind.agent.restart.completion.configDir should be defined"
fi

# T-ARESTART-2b: NEW — role completion reads roles from snapshot
test.case $level "T-ARESTART-2b: agent.restart.completion.role lists roles from snapshot" \
  type -t hiveMind.agent.restart.completion.role
if type -t hiveMind.agent.restart.completion.role &>/dev/null; then
  ROLE_LIST=$(hiveMind.agent.restart.completion.role "$PULL_FIXTURE" 2>/dev/null)
  if echo "$ROLE_LIST" | grep -q "remote-orchestrator" && \
     echo "$ROLE_LIST" | grep -q "remote-coder" && \
     echo "$ROLE_LIST" | grep -q "remote-tester"; then
    expect.pass "completion lists all 3 roles from fixture snapshot"
  else
    expect.fail "completion should list remote-orchestrator, remote-coder, remote-tester; got: $ROLE_LIST"
  fi
else
  expect.fail "hiveMind.agent.restart.completion.role should be defined"
fi

test.case $level "T-ARESTART-3: agent.restart with no args returns error" \
  hiveMind.agent.restart
if [ "$RETURN_VALUE" -ne 0 ]; then
  expect.pass "agent.restart rejects missing configDir arg"
else
  expect.fail "agent.restart should return non-zero without args"
fi

# T-ARESTART-3b: NEW — configDir but no role shows usage with available roles
test.case $level "T-ARESTART-3b: agent.restart with configDir but no role shows usage" \
  echo "testing no-role usage"
AR3B_OUTPUT=$(hiveMind.agent.restart "$PULL_FIXTURE" 2>&1)
AR3B_RC=$?
if [ "$AR3B_RC" -ne 0 ]; then
  if echo "$AR3B_OUTPUT" | grep -q "remote-orchestrator" && \
     echo "$AR3B_OUTPUT" | grep -q "remote-coder"; then
    expect.pass "no-role shows usage with available roles (rc=$AR3B_RC)"
  else
    expect.fail "no-role should list available roles in output; got: $AR3B_OUTPUT"
  fi
else
  expect.fail "agent.restart with configDir but no role should return non-zero"
fi

test.case $level "T-ARESTART-4: agent.restart with nonexistent dir returns error" \
  hiveMind.agent.restart "hivemind.nonexistent_$$"
if [ "$RETURN_VALUE" -ne 0 ]; then
  expect.pass "agent.restart rejects nonexistent directory"
else
  expect.fail "agent.restart should fail for nonexistent directory"
fi

# T-ARESTART-4b: NEW — unknown role returns error
test.case $level "T-ARESTART-4b: agent.restart with unknown role returns error" \
  echo "testing unknown role"
AR4B_OUTPUT=$(hiveMind.agent.restart "$PULL_FIXTURE" "nonexistent-role-$$" 2>&1)
AR4B_RC=$?
if [ "$AR4B_RC" -ne 0 ]; then
  if echo "$AR4B_OUTPUT" | grep -q "not found"; then
    expect.pass "unknown role returns error with 'not found' message (rc=$AR4B_RC)"
  else
    expect.pass "unknown role returns error (rc=$AR4B_RC) — message: $AR4B_OUTPUT"
  fi
else
  expect.fail "agent.restart with unknown role should return non-zero"
fi

mkdir -p "${TMPDIR:-/tmp}/hivemind.empty_$$"
test.case $level "T-ARESTART-5: agent.restart with empty dir returns error" \
  hiveMind.agent.restart "${TMPDIR:-/tmp}/hivemind.empty_$$" "some-role"
if [ "$RETURN_VALUE" -ne 0 ]; then
  expect.pass "agent.restart rejects empty directory (no snapshot)"
else
  expect.fail "agent.restart should fail for directory without snapshot"
fi
rm -rf "${TMPDIR:-/tmp}/hivemind.empty_$$"

# T-ARESTART-6..7 require tmux — single-role restart creates correct pane
if otmux sessions >/dev/null 2>&1; then

  # Create fixture for restart
  RESTART_FIXTURE="${TMPDIR:-/tmp}/hivemind.__test_restart_$$"
  mkdir -p "$RESTART_FIXTURE"
  cat > "$RESTART_FIXTURE/hivemind.snapshot.env" <<RSNAP
# hiveMind snapshot test-restart
# session|address|role|uuid|title
${TEST_ARESTART_SESS}|0.0|test-puller-alpha||alpha-pulled
${TEST_ARESTART_SESS}|0.1|test-puller-beta||beta-pulled
RSNAP
  cat > "$RESTART_FIXTURE/hivemind.roles.env" <<RROLES
${TEST_ARESTART_SESS}:0.0|test-puller-alpha
${TEST_ARESTART_SESS}:0.1|test-puller-beta
RROLES

  # Clean any prior test session
  otmux kill "$TEST_ARESTART_SESS" 2>/dev/null

  # T-ARESTART-6: Single role restart creates session and correct pane
  test.case $level "T-ARESTART-6: single-role restart creates session and pane" \
    echo "restarting test-puller-alpha from $RESTART_FIXTURE"
  if type -t hiveMind.agent.restart &>/dev/null; then
    hiveMind.agent.restart "$RESTART_FIXTURE" "test-puller-alpha" 2>/dev/null
    if otmux has "$TEST_ARESTART_SESS" 2>/dev/null; then
      expect.pass "session $TEST_ARESTART_SESS created for single role"
    else
      expect.fail "session $TEST_ARESTART_SESS not created by agent.restart"
    fi
  else
    expect.pass "skipped — agent.restart not yet implemented"
  fi

  # T-ARESTART-6b: Registry populated for the single role
  test.case $level "T-ARESTART-6b: single-role restart populates registry" \
    echo "checking registry"
  if type -t hiveMind.agent.restart &>/dev/null; then
    if grep -q "test-puller-alpha" "$REG_FILE" 2>/dev/null; then
      expect.pass "test-puller-alpha found in registry"
    else
      expect.fail "test-puller-alpha should be in registry after restart"
    fi
  else
    expect.pass "skipped — agent.restart not yet implemented"
  fi

  # T-ARESTART-6c: Only the requested role was restarted, not all roles
  test.case $level "T-ARESTART-6c: single-role restart does NOT create other roles" \
    echo "checking beta not started"
  if type -t hiveMind.agent.restart &>/dev/null; then
    if grep -q "test-puller-beta" "$REG_FILE" 2>/dev/null; then
      expect.fail "test-puller-beta should NOT be in registry — only alpha was requested"
    else
      expect.pass "only requested role was restarted"
    fi
  else
    expect.pass "skipped — agent.restart not yet implemented"
  fi

  # Cleanup single-role test
  otmux kill "$TEST_ARESTART_SESS" 2>/dev/null
  [ -f "$REG_FILE" ] && grep -v 'test-puller-' "$REG_FILE" > "${REG_FILE}.ar_clean" 2>/dev/null && mv "${REG_FILE}.ar_clean" "$REG_FILE"

  # T-ARESTART-7: Collision handling — session already exists
  otmux new "$TEST_ARESTART_SESS" 2>/dev/null
  test.case $level "T-ARESTART-7: restart handles session name collision" \
    echo "testing collision"
  if type -t hiveMind.agent.restart &>/dev/null; then
    hiveMind.agent.restart "$RESTART_FIXTURE" "test-puller-alpha" 2>/dev/null
    ARESTART_RC=$?
    if [ "$ARESTART_RC" -eq 0 ]; then
      expect.pass "agent.restart handled existing session (rc=0)"
    else
      expect.pass "agent.restart rejects collision (rc=$ARESTART_RC)"
    fi
  else
    expect.pass "skipped — agent.restart not yet implemented"
  fi

  # Cleanup restart tests
  otmux kill "$TEST_ARESTART_SESS" 2>/dev/null
  [ -f "$REG_FILE" ] && grep -v 'test-puller-' "$REG_FILE" > "${REG_FILE}.ar_clean" 2>/dev/null && mv "${REG_FILE}.ar_clean" "$REG_FILE"
  rm -rf "$RESTART_FIXTURE"

  # T-ARESTART-8: Dotted hostname → session name must be tmux-safe
  # Real bug: ${TMPDIR:-/tmp}/hivemind.UpDown.ai/ → hostName=UpDown.ai → session "UpDown.ai.sess"
  # tmux interprets dots as window.pane separators → "can't find session"
  DOT_FIXTURE="${TMPDIR:-/tmp}/hivemind.__test_dot_my.server.com_$$"
  DOT_SESS="__test_dotsess_$$"
  mkdir -p "$DOT_FIXTURE"
  cat > "$DOT_FIXTURE/hivemind.snapshot.env" <<DOTSNAP
# hiveMind snapshot dot-test
# session|address|role|uuid|title
${DOT_SESS}|0.0|dot-tester||dot-tester
DOTSNAP
  cat > "$DOT_FIXTURE/hivemind.roles.env" <<DOTROLES
${DOT_SESS}:0.0|dot-tester
DOTROLES

  # Pre-create session to force collision path → hostName prefix applied
  otmux new "$DOT_SESS" 2>/dev/null
  test.case $level "T-ARESTART-8: dotted hostname does not break tmux session creation" \
    echo "testing dotted hostname collision"
  AR8_OUTPUT=$(hiveMind.agent.restart "$DOT_FIXTURE" "dot-tester" 2>&1)
  AR8_RC=$?
  if [ "$AR8_RC" -eq 0 ]; then
    # Check that session was actually created (not just rc=0 with tmux error)
    AR8_SESSIONS=$(tmux list-sessions 2>/dev/null | grep -c "dot-tester\|dotsess" || true)
    if [ "$AR8_SESSIONS" -ge 1 ]; then
      expect.pass "session created despite dotted hostname"
    else
      expect.fail "rc=0 but no session found — dots in hostname likely broke tmux"
    fi
  else
    # Check if failure message mentions session/dot issue
    if echo "$AR8_OUTPUT" | grep -qi "session\|find\|dot"; then
      expect.fail "dotted hostname broke session creation: $AR8_OUTPUT"
    else
      expect.fail "agent.restart failed (rc=$AR8_RC): $AR8_OUTPUT"
    fi
  fi
  # Cleanup dot test
  otmux kill "$DOT_SESS" 2>/dev/null
  tmux list-sessions 2>/dev/null | grep "my.server.com\|dotsess" | cut -d: -f1 | while read s; do tmux kill-session -t "$s" 2>/dev/null; done
  [ -f "$REG_FILE" ] && grep -v 'dot-tester' "$REG_FILE" > "${REG_FILE}.dot_clean" 2>/dev/null && mv "${REG_FILE}.dot_clean" "$REG_FILE"
  rm -rf "$DOT_FIXTURE"

  # T-ARESTART-9: JSONL lookup actually finds files when present
  JSONL_FIXTURE="${TMPDIR:-/tmp}/hivemind.__test_jsonl_$$"
  JSONL_SESS="__test_jsonlsess_$$"
  JSONL_UUID="deadbeef-1234-5678-9abc-def012345678"
  mkdir -p "$JSONL_FIXTURE"
  cat > "$JSONL_FIXTURE/hivemind.snapshot.env" <<JSNAP
# hiveMind snapshot jsonl-test
# session|address|role|uuid|title
${JSONL_SESS}|0.0|jsonl-tester|${JSONL_UUID}|jsonl-tester
JSNAP
  cat > "$JSONL_FIXTURE/hivemind.roles.env" <<JROLES
${JSONL_SESS}:0.0|jsonl-tester
JROLES
  # Create a fake JSONL in a claude projects dir so the lookup finds it
  JSONL_PROJECT_DIR="$HOME/.claude/projects/__test_jsonl_project_$$"
  mkdir -p "$JSONL_PROJECT_DIR"
  echo '{"type":"test"}' > "$JSONL_PROJECT_DIR/${JSONL_UUID}.jsonl"

  test.case $level "T-ARESTART-9: JSONL present → agent.restart forks (not fresh)" \
    echo "testing JSONL lookup"
  AR9_OUTPUT=$(hiveMind.agent.restart "$JSONL_FIXTURE" "jsonl-tester" 2>&1)
  AR9_RC=$?
  if echo "$AR9_OUTPUT" | grep -q "fork"; then
    expect.pass "agent.restart chose fork path when JSONL exists"
  elif echo "$AR9_OUTPUT" | grep -q "fresh\|no JSONL"; then
    expect.fail "JSONL exists at $JSONL_PROJECT_DIR/${JSONL_UUID}.jsonl but agent.restart chose fresh start"
  else
    expect.fail "unexpected output: $AR9_OUTPUT"
  fi

  # T-ARESTART-10: JSONL absent → agent.restart starts fresh
  NOJSONL_UUID="00000000-0000-0000-0000-000000000000"
  cat > "$JSONL_FIXTURE/hivemind.snapshot.env" <<NJSNAP
# hiveMind snapshot no-jsonl-test
# session|address|role|uuid|title
${JSONL_SESS}|0.0|jsonl-tester|${NOJSONL_UUID}|jsonl-tester
NJSNAP
  otmux kill "$JSONL_SESS" 2>/dev/null
  test.case $level "T-ARESTART-10: no JSONL → agent.restart starts fresh" \
    echo "testing missing JSONL"
  AR10_OUTPUT=$(hiveMind.agent.restart "$JSONL_FIXTURE" "jsonl-tester" 2>&1)
  if echo "$AR10_OUTPUT" | grep -q "fresh\|no JSONL\|no UUID"; then
    expect.pass "agent.restart chose fresh start when JSONL missing"
  elif echo "$AR10_OUTPUT" | grep -q "fork"; then
    expect.fail "no JSONL for $NOJSONL_UUID but agent.restart tried to fork"
  else
    expect.pass "agent.restart completed (output: $AR10_OUTPUT)"
  fi

  # Cleanup JSONL tests
  otmux kill "$JSONL_SESS" 2>/dev/null
  rm -rf "$JSONL_FIXTURE" "$JSONL_PROJECT_DIR"
  [ -f "$REG_FILE" ] && grep -v 'jsonl-tester' "$REG_FILE" > "${REG_FILE}.jsonl_clean" 2>/dev/null && mv "${REG_FILE}.jsonl_clean" "$REG_FILE"

else
  test.case $level "T-ARESTART-6: single-role restart (skipped — no tmux)" echo "skip"
  expect.pass "skipped — tmux not available"
  test.case $level "T-ARESTART-6b: registry populated (skipped)" echo "skip"
  expect.pass "skipped"
  test.case $level "T-ARESTART-6c: only requested role (skipped)" echo "skip"
  expect.pass "skipped"
  test.case $level "T-ARESTART-7: collision handling (skipped)" echo "skip"
  expect.pass "skipped"
  test.case $level "T-ARESTART-8: dotted hostname (skipped)" echo "skip"
  expect.pass "skipped"
  test.case $level "T-ARESTART-9: JSONL fork (skipped)" echo "skip"
  expect.pass "skipped"
  test.case $level "T-ARESTART-10: no JSONL fresh (skipped)" echo "skip"
  expect.pass "skipped"
fi

echo ""
echo "=== agent.restart (single-role) tests complete ==="
echo ""

# ── B2. team.restart tests (renamed from old agent.restart) ─────────────────

test.case $level "T-TRESTART-1: team.restart function exists" \
  type -t hiveMind.team.restart
if type -t hiveMind.team.restart &>/dev/null; then
  expect.pass "hiveMind.team.restart function exists"
else
  expect.fail "hiveMind.team.restart should be defined (renamed from old agent.restart)"
fi

test.case $level "T-TRESTART-2: team.restart.completion.configDir exists" \
  type -t hiveMind.team.restart.completion.configDir
if type -t hiveMind.team.restart.completion.configDir &>/dev/null; then
  expect.pass "team.restart completion function exists"
else
  expect.fail "team.restart.completion.configDir should be defined"
fi

test.case $level "T-TRESTART-3: team.restart with no args returns error" \
  hiveMind.team.restart
if [ "$RETURN_VALUE" -ne 0 ]; then
  expect.pass "team.restart rejects missing configDir arg"
else
  expect.fail "team.restart should return non-zero without args"
fi

# T-TRESTART-4: team.restart creates ALL panes from fixture (tmux required)
if otmux sessions >/dev/null 2>&1; then
  TR_FIXTURE="${TMPDIR:-/tmp}/hivemind.__test_trestart_$$"
  TR_SESS="__test_trestart_$$"
  mkdir -p "$TR_FIXTURE"
  cat > "$TR_FIXTURE/hivemind.snapshot.env" <<TRSNAP
# hiveMind snapshot team-restart-test
# session|address|role|uuid|title
${TR_SESS}|0.0|tr-alpha||tr-alpha
${TR_SESS}|0.1|tr-beta||tr-beta
TRSNAP
  cat > "$TR_FIXTURE/hivemind.roles.env" <<TRROLES
${TR_SESS}:0.0|tr-alpha
${TR_SESS}:0.1|tr-beta
TRROLES

  otmux kill "$TR_SESS" 2>/dev/null
  test.case $level "T-TRESTART-4: team.restart creates ALL panes" \
    echo "restarting all from $TR_FIXTURE"
  if type -t hiveMind.team.restart &>/dev/null; then
    hiveMind.team.restart "$TR_FIXTURE" 2>/dev/null
    if otmux has "$TR_SESS" 2>/dev/null; then
      TR_PANES=$(otmux panes -t "$TR_SESS" -s 2>/dev/null | wc -l | tr -d ' ')
      TR_REG=$(grep "tr-alpha\|tr-beta" "$REG_FILE" 2>/dev/null | wc -l | tr -d ' ')
      if [ "$TR_PANES" -ge 2 ] && [ "$TR_REG" -ge 2 ]; then
        expect.pass "team.restart: $TR_PANES panes, $TR_REG registry entries"
      else
        expect.fail "team.restart: panes=$TR_PANES registry=$TR_REG"
      fi
    else
      expect.fail "team.restart session $TR_SESS not created"
    fi
  else
    expect.pass "skipped — team.restart not yet implemented"
  fi
  otmux kill "$TR_SESS" 2>/dev/null
  [ -f "$REG_FILE" ] && grep -v 'tr-alpha\|tr-beta' "$REG_FILE" > "${REG_FILE}.tr_clean" 2>/dev/null && mv "${REG_FILE}.tr_clean" "$REG_FILE"
  rm -rf "$TR_FIXTURE"
else
  test.case $level "T-TRESTART-4: team.restart all panes (skipped — no tmux)" echo "skip"
  expect.pass "skipped"
fi

echo ""
echo "=== team.restart tests complete ==="
echo ""

# ── C. Integration tests ────────────────────────────────────────────────────

# T-PULLRESTART-1: Round-trip fixture → single-role restart
if otmux sessions >/dev/null 2>&1; then
  RT_SESS="__test_roundtrip_$$"
  RT_FIXTURE="${TMPDIR:-/tmp}/hivemind.__test_roundtrip_$$"
  mkdir -p "$RT_FIXTURE"
  cat > "$RT_FIXTURE/hivemind.snapshot.env" <<RTSNAP
# hiveMind snapshot roundtrip-test
# session|address|role|uuid|title
${RT_SESS}|0.0|rt-alpha||rt-alpha
${RT_SESS}|0.1|rt-beta||rt-beta
RTSNAP
  cat > "$RT_FIXTURE/hivemind.roles.env" <<RTROLES
${RT_SESS}:0.0|rt-alpha
${RT_SESS}:0.1|rt-beta
RTROLES

  test.case $level "T-PULLRESTART-1: round-trip fixture → single-role restart" \
    echo "roundtrip test"
  if type -t hiveMind.agent.restart &>/dev/null; then
    otmux kill "$RT_SESS" 2>/dev/null
    hiveMind.agent.restart "$RT_FIXTURE" "rt-alpha" 2>/dev/null
    if otmux has "$RT_SESS" 2>/dev/null; then
      RT_REG=$(grep "rt-alpha" "$REG_FILE" 2>/dev/null | wc -l | tr -d ' ')
      if [ "$RT_REG" -ge 1 ]; then
        expect.pass "roundtrip: rt-alpha registered"
      else
        expect.fail "roundtrip: rt-alpha not in registry"
      fi
    else
      expect.fail "roundtrip session $RT_SESS not created"
    fi
  else
    expect.pass "skipped — agent.restart not yet implemented"
  fi
  otmux kill "$RT_SESS" 2>/dev/null
  [ -f "$REG_FILE" ] && grep -v 'rt-alpha\|rt-beta' "$REG_FILE" > "${REG_FILE}.rt_clean" 2>/dev/null && mv "${REG_FILE}.rt_clean" "$REG_FILE"
  rm -rf "$RT_FIXTURE"
else
  test.case $level "T-PULLRESTART-1: round-trip (skipped — no tmux)" echo "skip"
  expect.pass "skipped"
fi

# T-PULLRESTART-2: Non-regression — agent.restart.remote still exists
test.case $level "T-PULLRESTART-2: agent.restart.remote not clobbered" \
  type -t hiveMind.agent.restart.remote
if type -t hiveMind.agent.restart.remote &>/dev/null; then
  if type -t hiveMind.agent.restart.remote.completion.agentName &>/dev/null && \
     type -t hiveMind.agent.restart.remote.completion.host &>/dev/null; then
    expect.pass "agent.restart.remote + completions still exist"
  else
    expect.fail "agent.restart.remote completions missing"
  fi
else
  expect.fail "agent.restart.remote function clobbered!"
fi

echo ""
echo "=== team.pull + agent.restart integration tests complete ==="
echo ""

# ── T-SCP: raw scp elimination — all transfers must use ossh ControlPath ──────

# T-SCP-1: No raw scp calls without ControlPath in hiveMind
SCP1_RAW=$(grep -n '\bscp\b' "$OOSH_DIR/hiveMind" 2>/dev/null | grep -v 'ControlPath\|OSSH_CONTROL\|ossh.*scp\|#.*scp\|error.*scp\|echo.*scp\|log.*scp' | wc -l | tr -d ' ')
test.case $level "T-SCP-1: zero raw scp calls without ControlPath in hiveMind" echo "raw_scp=$SCP1_RAW"
if [ "$SCP1_RAW" -eq 0 ]; then
  expect.pass "all scp calls use ControlPath or ossh wrapper"
else
  expect.fail "found $SCP1_RAW raw scp calls without ControlPath — each asks for password"
fi

# T-SCP-2: team.pull uses ossh ControlPath for ALL transfers
SCP2_PULL_LINES=$(sed -n '/^hiveMind\.team\.pull()/,/^[a-zA-Z].*().*#/p' "$OOSH_DIR/hiveMind" 2>/dev/null)
SCP2_RAW_IN_PULL=$(echo "$SCP2_PULL_LINES" | grep '\bscp\b' | grep -v 'ControlPath\|OSSH_CONTROL\|ossh\|#.*scp\|log.*scp' | wc -l | tr -d ' ')
test.case $level "T-SCP-2: team.pull has zero raw scp calls" echo "raw_in_pull=$SCP2_RAW_IN_PULL"
if [ "$SCP2_RAW_IN_PULL" -eq 0 ]; then
  expect.pass "team.pull transfers all use ControlPath"
else
  expect.fail "team.pull has $SCP2_RAW_IN_PULL raw scp calls — password per file"
fi

# T-SCP-3: teams.migrate uses ossh ControlPath for ALL transfers
SCP3_MIG_LINES=$(sed -n '/^hiveMind\.teams\.migrate()/,/^[a-zA-Z].*().*#/p' "$OOSH_DIR/hiveMind" 2>/dev/null)
SCP3_RAW_IN_MIG=$(echo "$SCP3_MIG_LINES" | grep '\bscp\b' | grep -v 'ControlPath\|OSSH_CONTROL\|ossh\|#.*scp\|log.*scp' | wc -l | tr -d ' ')
test.case $level "T-SCP-3: teams.migrate has zero raw scp calls" echo "raw_in_migrate=$SCP3_RAW_IN_MIG"
if [ "$SCP3_RAW_IN_MIG" -eq 0 ]; then
  expect.pass "teams.migrate transfers all use ControlPath"
else
  expect.fail "teams.migrate has $SCP3_RAW_IN_MIG raw scp calls — password per file"
fi

# T-SCP-4: task.transfer uses ossh ControlPath
SCP4_XFER_LINES=$(sed -n '/^private\.hiveMind\.task\.transfer()/,/^[a-zA-Z].*().*#/p' "$OOSH_DIR/hiveMind" 2>/dev/null)
SCP4_RAW_IN_XFER=$(echo "$SCP4_XFER_LINES" | grep '\bscp\b' | grep -v 'ControlPath\|OSSH_CONTROL\|ossh\|#.*scp\|log.*scp' | wc -l | tr -d ' ')
test.case $level "T-SCP-4: task.transfer has zero raw scp calls" echo "raw_in_transfer=$SCP4_RAW_IN_XFER"
if [ "$SCP4_RAW_IN_XFER" -eq 0 ]; then
  expect.pass "task.transfer uses ControlPath"
else
  expect.fail "task.transfer has $SCP4_RAW_IN_XFER raw scp calls"
fi

# T-SCP-5: agent.restart.remote uses ossh ControlPath
SCP5_REMOTE_LINES=$(sed -n '/^hiveMind\.agent\.restart\.remote()/,/^[a-zA-Z].*().*#/p' "$OOSH_DIR/hiveMind" 2>/dev/null)
SCP5_RAW_IN_REMOTE=$(echo "$SCP5_REMOTE_LINES" | grep '\bscp\b' | grep -v 'ControlPath\|OSSH_CONTROL\|ossh\|#.*scp\|log.*scp' | wc -l | tr -d ' ')
test.case $level "T-SCP-5: agent.restart.remote has zero raw scp calls" echo "raw_in_remote=$SCP5_RAW_IN_REMOTE"
if [ "$SCP5_RAW_IN_REMOTE" -eq 0 ]; then
  expect.pass "agent.restart.remote uses ControlPath"
else
  expect.fail "agent.restart.remote has $SCP5_RAW_IN_REMOTE raw scp calls"
fi

# T-SCP-6: No raw ssh calls without ControlPath (excluding comments/logs)
SCP6_RAW_SSH=$(grep -n '\bssh\b' "$OOSH_DIR/hiveMind" 2>/dev/null | grep -v 'ControlPath\|OSSH_CONTROL\|ossh\|#.*ssh\|echo.*ssh\|log.*ssh\|sshHost\|sshConfig\|SSH\|\.ssh\|sed.*ssh' | wc -l | tr -d ' ')
test.case $level "T-SCP-6: zero raw ssh calls without ControlPath in hiveMind" echo "raw_ssh=$SCP6_RAW_SSH"
if [ "$SCP6_RAW_SSH" -eq 0 ]; then
  expect.pass "all ssh calls use ControlPath or ossh wrapper"
else
  expect.fail "found $SCP6_RAW_SSH raw ssh calls without ControlPath"
fi

# T-SCP-7: ossh.scp method exists (OOSH wrapper for scp)
test.case $level "T-SCP-7: ossh has scp or file.copy method" \
  bash -c "grep -q 'ossh\.scp\|ossh\.file\.copy\|private\.ossh\.rsync' $OOSH_DIR/ossh"
if grep -q 'ossh\.scp\|ossh\.file\.copy\|private\.ossh\.rsync' "$OOSH_DIR/ossh" 2>/dev/null; then
  expect.pass "ossh has transfer wrapper method"
else
  expect.fail "ossh needs scp/file.copy method — OOSH rule: never use raw system commands where wrapper exists"
fi

# T-SCP-8: In team.pull, connection.open precedes any scp/ossh-scp calls
SCP8_PULL_BODY=$(sed -n '/^hiveMind\.team\.pull()/,/^[a-zA-Z].*().*#/p' "$OOSH_DIR/hiveMind" 2>/dev/null)
SCP8_CONN_REL=$(echo "$SCP8_PULL_BODY" | grep -n 'connection\.open' | head -1 | cut -d: -f1)
SCP8_SCP_REL=$(echo "$SCP8_PULL_BODY" | grep -n 'scp\b' | grep -v '#.*scp\|log.*scp' | head -1 | cut -d: -f1)
test.case $level "T-SCP-8: team.pull connection.open precedes first scp" echo "conn=$SCP8_CONN_REL scp=$SCP8_SCP_REL"
if [ -n "$SCP8_CONN_REL" ] && [ -n "$SCP8_SCP_REL" ] && [ "$SCP8_CONN_REL" -lt "$SCP8_SCP_REL" ]; then
  expect.pass "connection.open (rel line $SCP8_CONN_REL) before first scp (rel line $SCP8_SCP_REL) in team.pull"
else
  expect.fail "team.pull: connection.open must precede scp calls (conn=$SCP8_CONN_REL scp=$SCP8_SCP_REL)"
fi

echo ""
echo "=== T-SCP: raw scp/ssh elimination tests complete ==="
echo ""

# ============================================================================
# FEATURE: Fork UUID auto-registration in sessions.env
# Bug: after claudeCode fork, sessions.env keeps parent UUID. Child UUID
# only discovered later by consistency.fix. Must be captured immediately.
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"
CLAUDECODE_SRC="$OOSH_DIR/claudeCode"

# --- T-FORK-1: every fork call site must have post-fork UUID capture ---
# Find lines that send "claudeCode fork" to a pane
FORK_SENDS=$(grep -n 'claudeCode fork' "$HIVEMIND_SRC" | grep -v '^\s*#\|grep\|echo.*fork\|log.*fork' | wc -l | tr -d ' ')
# Find lines that call session.resolve.uuid or session.probe after fork
FORK_CAPTURES=$(grep -n 'session\.resolve\.uuid\|session\.probe\|session\.store' "$HIVEMIND_SRC" | wc -l | tr -d ' ')
test.case $level "T-FORK-1: fork call sites exist in hiveMind" echo "fork_sends=$FORK_SENDS"
if [ "$FORK_SENDS" -gt 0 ]; then
  expect.pass "$FORK_SENDS fork call sites found"
else
  expect.fail "no claudeCode fork calls found in hiveMind"
fi

# --- T-FORK-2: post-fork UUID capture exists near fork calls ---
# For each fork send, there should be a resolve/probe/store within 10 lines after
FORK_UNCAPTURED=0
FORK_UNCAPTURED_LOCS=""
while IFS=: read -r linenum content; do
  [ -z "$linenum" ] && continue
  # Check next 15 lines for session resolve/probe/store
  end=$((linenum + 15))
  HAS_CAPTURE=$(sed -n "${linenum},${end}p" "$HIVEMIND_SRC" | grep -c 'session\.resolve\.uuid\|session\.probe\|session\.store\|sessions\.env')
  if [ "$HAS_CAPTURE" -eq 0 ]; then
    FORK_UNCAPTURED=$((FORK_UNCAPTURED + 1))
    FORK_UNCAPTURED_LOCS="${FORK_UNCAPTURED_LOCS} L${linenum}"
  fi
done <<< "$(grep -n 'claudeCode fork' "$HIVEMIND_SRC" | grep -v '^\s*#\|grep\|echo.*fork\|log.*fork')"
test.case $level "T-FORK-2: all fork sites have post-fork UUID capture" echo "uncaptured=$FORK_UNCAPTURED"
if [ "$FORK_UNCAPTURED" -eq 0 ]; then
  expect.pass "all fork sites capture child UUID"
else
  expect.fail "$FORK_UNCAPTURED fork sites without UUID capture:$FORK_UNCAPTURED_LOCS"
fi

# --- T-FORK-3: session.resolve.uuid writes through to sessions.env ---
# The resolve function should update sessions.env when it finds a new UUID
RESOLVE_BODY=$(sed -n '/^private\.hiveMind\.session\.resolve\.uuid()/,/^}/p' "$HIVEMIND_SRC")
RESOLVE_WRITES=$(echo "$RESOLVE_BODY" | grep -c 'sessions\.env\|HIVEMIND_SESSIONS\|sesFile')
test.case $level "T-FORK-3: session.resolve.uuid writes through to sessions.env" echo "writes=$RESOLVE_WRITES"
if [ "$RESOLVE_WRITES" -gt 0 ]; then
  expect.pass "resolve has sessions.env write-through ($RESOLVE_WRITES refs)"
else
  expect.fail "resolve must update sessions.env when finding new UUID"
fi

# --- T-FORK-4: teams.restore --fork path captures child UUIDs ---
RESTORE_BODY=$(sed -n '/^hiveMind\.teams\.restore()/,/^[a-zA-Z].*().*#/p' "$HIVEMIND_SRC")
RESTORE_FORK_CAPTURE=$(echo "$RESTORE_BODY" | grep -c 'session\.resolve\.uuid\|session\.probe\|session\.store')
test.case $level "T-FORK-4: teams.restore captures child UUID after fork" echo "captures=$RESTORE_FORK_CAPTURE"
if [ "$RESTORE_FORK_CAPTURE" -gt 0 ]; then
  expect.pass "teams.restore has post-fork UUID capture"
else
  expect.fail "teams.restore must capture child UUID after claudeCode fork"
fi

# --- T-FORK-5: agent.restart captures child UUID after fork ---
ARESTART_BODY=$(sed -n '/^hiveMind\.agent\.restart()/,/^[a-zA-Z].*().*#/p' "$HIVEMIND_SRC")
ARESTART_FORK_CAPTURE=$(echo "$ARESTART_BODY" | grep -c 'session\.resolve\.uuid\|session\.probe\|session\.store')
test.case $level "T-FORK-5: agent.restart captures child UUID after fork" echo "captures=$ARESTART_FORK_CAPTURE"
if [ "$ARESTART_FORK_CAPTURE" -gt 0 ]; then
  expect.pass "agent.restart has post-fork UUID capture"
else
  expect.fail "agent.restart must capture child UUID after claudeCode fork"
fi

# --- T-FORK-6: agent.restart.remote captures child UUID after fork ---
REMOTE_BODY=$(sed -n '/^hiveMind\.agent\.restart\.remote()/,/^[a-zA-Z].*().*#/p' "$HIVEMIND_SRC")
REMOTE_FORK_CAPTURE=$(echo "$REMOTE_BODY" | grep -c 'session\.resolve\.uuid\|session\.probe\|session\.store')
test.case $level "T-FORK-6: agent.restart.remote captures child UUID after fork" echo "captures=$REMOTE_FORK_CAPTURE"
if [ "$REMOTE_FORK_CAPTURE" -gt 0 ]; then
  expect.pass "agent.restart.remote has post-fork UUID capture"
else
  expect.fail "agent.restart.remote must capture child UUID after fork"
fi

echo ""
echo "=== fork UUID auto-registration tests complete ==="
echo ""

# ============================================================================
# FEATURE: Agent snapshots + respawn (golden fork-source per role)
# T-SNAP-1..10 — TDD: written before implementation
# Tests run with HIVEMIND_SNAPSHOTS overridden to a tmp file so live config
# is untouched. Teardown removes the tmp file at the end.
# ============================================================================

TEST_SNAP_FILE="${TMPDIR:-/tmp}/__test_snap_$$.env"
ORIG_HIVEMIND_SNAPSHOTS="${HIVEMIND_SNAPSHOTS:-}"
export HIVEMIND_SNAPSHOTS="$TEST_SNAP_FILE"
rm -f "$TEST_SNAP_FILE"

# --- T-SNAP-1: function existence ---
test.case $level "T-SNAP-1: hiveMind.agent.snapshot function exists" \
  type -t hiveMind.agent.snapshot
if type -t hiveMind.agent.snapshot &>/dev/null; then
  expect.pass "hiveMind.agent.snapshot is defined"
else
  expect.fail "hiveMind.agent.snapshot missing"
fi

test.case $level "T-SNAP-1b: hiveMind.snapshot.list function exists" \
  type -t hiveMind.snapshot.list
if type -t hiveMind.snapshot.list &>/dev/null; then
  expect.pass "hiveMind.snapshot.list is defined"
else
  expect.fail "hiveMind.snapshot.list missing"
fi

test.case $level "T-SNAP-1c: hiveMind.agent.respawn function exists" \
  type -t hiveMind.agent.respawn
if type -t hiveMind.agent.respawn &>/dev/null; then
  expect.pass "hiveMind.agent.respawn is defined"
else
  expect.fail "hiveMind.agent.respawn missing"
fi

# --- T-SNAP-2: private.snapshot.set writes 4-field entry ---
test.case $level "T-SNAP-2: private.snapshot.set writes role|uuid|ts|ctx" \
  echo "testing set"
if type -t private.hiveMind.snapshot.set &>/dev/null; then
  rm -f "$TEST_SNAP_FILE"
  private.hiveMind.snapshot.set "test-role-$$" "aaaabbbb-cccc-dddd-eeee-ffffffffffff" "25.5" 2>/dev/null
  LINE=$(grep "^test-role-$$|" "$TEST_SNAP_FILE" 2>/dev/null)
  FIELDS=$(echo "$LINE" | awk -F'|' '{print NF}')
  if [ "$FIELDS" -eq 4 ] && echo "$LINE" | grep -q "aaaabbbb"; then
    expect.pass "4-field entry written: $LINE"
  else
    expect.fail "expected 4 fields with uuid, got '$LINE' ($FIELDS fields)"
  fi
else
  expect.fail "private.hiveMind.snapshot.set missing"
fi

# --- T-SNAP-3: re-snapshot replaces (no duplicates) ---
test.case $level "T-SNAP-3: private.snapshot.set upserts (no duplicates)" \
  echo "testing upsert"
if type -t private.hiveMind.snapshot.set &>/dev/null; then
  private.hiveMind.snapshot.set "test-role-$$" "11112222-3333-4444-5555-666677778888" "30.0" 2>/dev/null
  COUNT=$(grep -c "^test-role-$$|" "$TEST_SNAP_FILE" 2>/dev/null)
  LATEST=$(grep "^test-role-$$|" "$TEST_SNAP_FILE" | cut -d'|' -f2)
  if [ "$COUNT" -eq 1 ] && [ "$LATEST" = "11112222-3333-4444-5555-666677778888" ]; then
    expect.pass "single entry with latest uuid"
  else
    expect.fail "expected 1 entry with latest uuid, got count=$COUNT latest=$LATEST"
  fi
else
  expect.fail "skipped — set not implemented"
fi

# --- T-SNAP-4: private.snapshot.get round-trips ---
test.case $level "T-SNAP-4: private.snapshot.get round-trips" \
  echo "testing get"
if type -t private.hiveMind.snapshot.get &>/dev/null; then
  GOT=$(private.hiveMind.snapshot.get "test-role-$$" 2>/dev/null)
  GOT_UUID=$(echo "$GOT" | cut -d'|' -f1)
  if [ "$GOT_UUID" = "11112222-3333-4444-5555-666677778888" ]; then
    expect.pass "get returned uuid from latest set"
  else
    expect.fail "expected 11112222-... got '$GOT'"
  fi
else
  expect.fail "private.hiveMind.snapshot.get missing"
fi

# --- T-SNAP-5: snapshot.list shows registered entries ---
test.case $level "T-SNAP-5: snapshot.list prints registered role" \
  echo "testing list"
if type -t hiveMind.snapshot.list &>/dev/null; then
  LIST_OUT=$(hiveMind.snapshot.list 2>/dev/null)
  if echo "$LIST_OUT" | grep -q "test-role-$$"; then
    expect.pass "list includes test-role-$$"
  else
    expect.fail "list should show test-role-$$, got: $LIST_OUT"
  fi
else
  expect.fail "skipped — snapshot.list not implemented"
fi

# --- T-SNAP-6: snapshot.list flags missing JSONL as stale ---
test.case $level "T-SNAP-6: snapshot.list flags stale entries" \
  echo "testing stale detection"
if type -t hiveMind.snapshot.list &>/dev/null; then
  # test-role-$$ UUID is bogus — JSONL does not exist on disk
  LIST_OUT=$(hiveMind.snapshot.list 2>/dev/null | sed 's/\x1b\[[0-9;]*m//g')
  if echo "$LIST_OUT" | grep -iq "stale"; then
    expect.pass "list marks bogus UUID as stale"
  else
    expect.fail "list should mark bogus UUID as stale, got: $LIST_OUT"
  fi
else
  expect.fail "skipped — snapshot.list not implemented"
fi

# --- T-SNAP-7: agent.respawn has completion for agentName ---
test.case $level "T-SNAP-7: agent.respawn.completion.agentName exists" \
  type -t hiveMind.agent.respawn.completion.agentName
if type -t hiveMind.agent.respawn.completion.agentName &>/dev/null; then
  expect.pass "completion function defined"
else
  expect.fail "hiveMind.agent.respawn.completion.agentName missing"
fi

# --- T-SNAP-8: agent.respawn fails when no snapshot for role ---
test.case $level "T-SNAP-8: agent.respawn fails for role without snapshot" \
  echo "testing missing snapshot"
if type -t hiveMind.agent.respawn &>/dev/null; then
  # Use a role that surely has no snapshot AND no resolving pane
  hiveMind.agent.respawn "__nonexistent_role_$$" 2>/dev/null
  SNAP8_RC=$?
  if [ "$SNAP8_RC" -ne 0 ]; then
    expect.pass "respawn rejects unknown role/snapshot (rc=$SNAP8_RC)"
  else
    expect.fail "respawn should return non-zero for missing snapshot"
  fi
else
  expect.fail "skipped — agent.respawn not implemented"
fi

# --- T-SNAP-9: agent.respawn fails when snapshot JSONL is stale ---
test.case $level "T-SNAP-9: agent.respawn fails when snapshot JSONL missing" \
  echo "testing stale snapshot"
if type -t hiveMind.agent.respawn &>/dev/null; then
  # Snapshot points at bogus uuid that has no JSONL
  # Need a registered role for hiveMind.resolve to succeed, pointing at non-live pane.
  SNAP9_REG="${HIVEMIND_REGISTRY:-${CONFIG_PATH:-$HOME/config}/hivemind.roles.env}"
  SNAP9_ROLE="__snap9_role_$$"
  SNAP9_PANE="__snap9_sess_$$:0.0"
  echo "${SNAP9_PANE}|${SNAP9_ROLE}" >> "$SNAP9_REG"
  private.hiveMind.snapshot.set "$SNAP9_ROLE" "deadbeef-dead-dead-dead-deaddeaddead" "30.0" 2>/dev/null
  hiveMind.agent.respawn "$SNAP9_ROLE" 2>/dev/null
  SNAP9_RC=$?
  # Clean registry entry
  [ -f "$SNAP9_REG" ] && grep -v "^${SNAP9_PANE}|" "$SNAP9_REG" > "${SNAP9_REG}.sn9" 2>/dev/null && mv "${SNAP9_REG}.sn9" "$SNAP9_REG"
  if [ "$SNAP9_RC" -ne 0 ]; then
    expect.pass "respawn rejects stale snapshot (rc=$SNAP9_RC)"
  else
    expect.fail "respawn should return non-zero for stale snapshot JSONL"
  fi
else
  expect.fail "skipped — agent.respawn not implemented"
fi

# --- T-SNAP-10: snapshot CRUD does not leak into live config on fresh path ---
test.case $level "T-SNAP-10: test-tmp snapshots.env isolated from live config" \
  echo "testing isolation"
LIVE_SNAP_FILE="${CONFIG_PATH:-$HOME/config}/hivemind.snapshots.env"
if [ -f "$LIVE_SNAP_FILE" ]; then
  if grep -q "test-role-$$\|__snap9_role_$$" "$LIVE_SNAP_FILE" 2>/dev/null; then
    expect.fail "test entries leaked into $LIVE_SNAP_FILE"
  else
    expect.pass "live snapshots.env untouched"
  fi
else
  expect.pass "no live snapshots.env (fresh state)"
fi

# --- T-SNAP-11: Multiple roles both show in snapshot.list ---
test.case $level "T-SNAP-11: multiple roles in snapshot.list" \
  echo "testing multi-role list"
if type -t private.hiveMind.snapshot.set &>/dev/null && type -t hiveMind.snapshot.list &>/dev/null; then
  rm -f "$TEST_SNAP_FILE"
  private.hiveMind.snapshot.set "role-alpha-$$" "aaaa1111-2222-3333-4444-555566667777" "20.0" 2>/dev/null
  private.hiveMind.snapshot.set "role-beta-$$" "bbbb1111-2222-3333-4444-555566667777" "35.0" 2>/dev/null
  LIST_OUT=$(hiveMind.snapshot.list 2>/dev/null)
  if echo "$LIST_OUT" | grep -q "role-alpha-$$" && echo "$LIST_OUT" | grep -q "role-beta-$$"; then
    expect.pass "both roles appear in snapshot.list"
  else
    expect.fail "expected both roles in list, got: $LIST_OUT"
  fi
else
  expect.fail "skipped — set/list not implemented"
fi

# --- T-SNAP-12: snapshot.list with no snapshots file (fresh install) ---
test.case $level "T-SNAP-12: snapshot.list handles missing file gracefully" \
  echo "testing fresh install"
if type -t hiveMind.snapshot.list &>/dev/null; then
  rm -f "$TEST_SNAP_FILE"
  LIST_OUT=$(hiveMind.snapshot.list 2>/dev/null)
  SNAP12_RC=$?
  # Should not error — either returns 0 with empty/message, or exits cleanly
  if [ "$SNAP12_RC" -eq 0 ]; then
    expect.pass "snapshot.list handles missing file (rc=0)"
  else
    expect.fail "snapshot.list should not error on missing file (rc=$SNAP12_RC)"
  fi
else
  expect.fail "skipped — snapshot.list not implemented"
fi

# --- Cleanup snapshot tests ---
rm -f "$TEST_SNAP_FILE"
export HIVEMIND_SNAPSHOTS="$ORIG_HIVEMIND_SNAPSHOTS"

echo ""
echo "=== agent snapshot/respawn tests complete ==="
echo ""

# ============================================================================
# BUG-FIX TESTS — three PO-reported bugs (2026-04-15)
#  1. resolve picks wrong team when stale active-team file
#  2. team.monitor mis-parsed agent name as lines
#  3. teams.save used pane title instead of customTitle
# ============================================================================

# --- T-RESOLVE-ACTIVE: resolve must prefer active team when role is in multiple ---
test.case $level "T-RESOLVE-ACTIVE: active.team skips stale session file" \
  echo "testing stale-active guard"
ACTIVE_TEAM_FILE="${HIVEMIND_ACTIVE_TEAM_FILE:-${CONFIG_PATH:-$HOME/config}/hivemind.active.team}"
SAVED_ACTIVE="$(cat "$ACTIVE_TEAM_FILE" 2>/dev/null || true)"
# Point active to a session that does NOT exist in tmux
echo "__stale_session_for_resolve_$$" > "$ACTIVE_TEAM_FILE"
RESOLVED_ACTIVE="$(private.hiveMind.active.team 2>/dev/null)"
# Restore
if [ -n "$SAVED_ACTIVE" ]; then
  echo "$SAVED_ACTIVE" > "$ACTIVE_TEAM_FILE"
else
  rm -f "$ACTIVE_TEAM_FILE"
fi
if [ "$RESOLVED_ACTIVE" != "__stale_session_for_resolve_$$" ] && [ -n "$RESOLVED_ACTIVE" ]; then
  expect.pass "stale active-team ignored; fell through to live team '$RESOLVED_ACTIVE'"
else
  expect.fail "active.team returned stale/empty: '$RESOLVED_ACTIVE'"
fi

test.case $level "T-RESOLVE-SCOPE: resolve has debug.log per scope" \
  echo "checking resolve scopes"
if grep -q 'debug\.log "resolve:' "$OOSH_DIR/hiveMind"; then
  expect.pass "resolve emits scope hints via debug.log"
else
  expect.fail "resolve should log which scope matched for diagnosability"
fi

# --- T-TEAM-MONITOR-FILTER: agent-name vs numeric second arg ---
test.case $level "T-TEAM-MONITOR-FILTER: signature advertises 3 args" \
  echo "checking signature comment"
if grep -qE '^hiveMind\.team\.monitor\(\) # <\?session> <\?agentName> <\?lines' "$OOSH_DIR/hiveMind"; then
  expect.pass "team.monitor signature is <?session> <?agentName> <?lines>"
else
  expect.fail "team.monitor signature must declare optional agentName between session and lines"
fi

test.case $level "T-TEAM-MONITOR-FILTER: numeric backcompat path preserved" \
  echo "checking numeric branch"
if grep -qE '\[\[ "\$2" =~ \^\[0-9\]\+\$ \]\]' "$OOSH_DIR/hiveMind"; then
  expect.pass "team.monitor treats numeric \$2 as lines (back-compat)"
else
  expect.fail "team.monitor lost numeric-\$2 back-compat branch"
fi

test.case $level "T-TEAM-MONITOR-FILTER: agent resolution uses rc + format validation" \
  echo "checking filter validation"
TM_BODY=$(sed -n '/^hiveMind\.team\.monitor()/,/^}/p' "$OOSH_DIR/hiveMind")
if echo "$TM_BODY" | grep -q 'filterRc' && echo "$TM_BODY" | grep -qE '\[A-Za-z0-9_.-\]\+:\[0-9\]\+\\\.\[0-9\]\+'; then
  expect.pass "team.monitor validates resolve rc AND pane-address format"
else
  expect.fail "team.monitor must check both rc and pane format (error.log writes to stdout)"
fi

# --- T-SAVE-CUSTOMTITLE: teams.save prefers customTitle over pane title ---
test.case $level "T-SAVE-CUSTOMTITLE: role cascade is live → registry → role.fromTitle → unknown" \
  echo "checking cascade"
SV_BODY=$(sed -n '/^hiveMind\.teams\.save()/,/^}/p' "$OOSH_DIR/hiveMind")
# Expect all four links and NO raw '${title}' assignment (the old bug)
if echo "$SV_BODY" | grep -q 'private.hiveMind.live.discover' && \
   echo "$SV_BODY" | grep -q 'private.hiveMind.registry.get' && \
   echo "$SV_BODY" | grep -q 'private.hiveMind.role.fromTitle' && \
   ! echo "$SV_BODY" | grep -qE '^\s*role="\$\{title\}"'; then
  expect.pass "teams.save cascade correct (no raw pane-title fallback)"
else
  expect.fail "teams.save must use role.fromTitle, not raw \${title} as role"
fi

test.case $level "T-SAVE-CUSTOMTITLE: DRY — no inline prefix/@model stripping in teams.save" \
  echo "checking for redundant cleanup"
INLINE_STRIPS=$(echo "$SV_BODY" | grep -cE '\$\{role#✳ \}|\$\{role%%@\*\}|tr -d .\[:space:\]' | tr -d ' ')
if [ "${INLINE_STRIPS:-0}" -eq 0 ]; then
  expect.pass "teams.save delegates cleanup to role.fromTitle (DRY)"
else
  expect.fail "teams.save still has $INLINE_STRIPS inline strip statements — should use role.fromTitle"
fi

echo ""
echo "=== three-bug-fix regression tests complete ==="
echo ""

# --- Cleanup pull/restart test artifacts ---
rm -rf "$TEST_PULL_DIR" "$PULL_FIXTURE" ${TMPDIR:-/tmp}/hivemind.__test_* ${TMPDIR:-/tmp}/hivemind.nonexistent-*
rm -rf "$TEST_SSH_DIR"
export CURRENT_SSH_DIR="$ORIG_SSH_DIR"
# Clean registry entries from restart tests
[ -f "$REG_FILE" ] && grep -v 'test-puller-\|rt-alpha\|rt-beta\|tr-alpha\|tr-beta\|remote-' "$REG_FILE" > "${REG_FILE}.pr_clean" 2>/dev/null && mv "${REG_FILE}.pr_clean" "$REG_FILE"

# ============================================================================
# Cleanup — kill ALL test sessions and remove stale registry entries
# ============================================================================

otmux kill "$TEST_SESSION" 2>/dev/null
__test_cleanup "__test_lifecycle_$$"
__test_cleanup "__test_arestart_$$"
__test_cleanup "__test_trestart_$$"
__test_cleanup "__test_roundtrip_$$"

# Catch-all: kill ANY __test_ session left by this or previous runs
# This prevents stale sessions from accumulating across test runs
tmux list-sessions 2>/dev/null | grep '__test_' | cut -d: -f1 | while read stale; do
  tmux kill-session -t "$stale" 2>/dev/null
done

[ -f "$REG_FILE" ] && grep -v '__test_' "$REG_FILE" > "${REG_FILE}.clean" 2>/dev/null && mv "${REG_FILE}.clean" "$REG_FILE"

# ============================================================================
# FEATURE: registry.refresh — non-invasive UUID tracking
# Uses claudeCode.session.discover (no /status hijack)
# Writes roles.env + sessions.env + forks.env (append-only)
# Prunes dead panes from both roles.env AND sessions.env
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"

# ============================================================================
# FEATURE: multi-team resolve (03149ef)
# Searches all teams, disambiguates by caller session, errors on ambiguity
# ============================================================================

# Setup: add entries for 2 fake teams with overlapping role name
RESOLVE_REG="$HIVEMIND_REGISTRY"
RESOLVE_TEAM_A="__test_resolve_a_$$"
RESOLVE_TEAM_B="__test_resolve_b_$$"
# unique-agent only in team A, shared-agent in both, lonely-agent only in B
echo "${RESOLVE_TEAM_A}:0.0|unique-agent-$$" >> "$RESOLVE_REG"
echo "${RESOLVE_TEAM_A}:0.1|shared-agent-$$" >> "$RESOLVE_REG"
echo "${RESOLVE_TEAM_B}:0.0|shared-agent-$$" >> "$RESOLVE_REG"
echo "${RESOLVE_TEAM_B}:0.1|lonely-agent-$$" >> "$RESOLVE_REG"
# Create tmux sessions so pane verification passes
otmux new "$RESOLVE_TEAM_A" -d 2>/dev/null
otmux split "${RESOLVE_TEAM_A}:0.0" -d 2>/dev/null
otmux new "$RESOLVE_TEAM_B" -d 2>/dev/null
otmux split "${RESOLVE_TEAM_B}:0.0" -d 2>/dev/null

# --- T-RESOLVE-MT-1: explicit session searches only there ---
test.case $level "T-RESOLVE-MT-1: explicit session scopes search" \
  hiveMind.resolve "unique-agent-$$" "$RESOLVE_TEAM_A"
RESOLVE_MT1=$(hiveMind.resolve "unique-agent-$$" "$RESOLVE_TEAM_A" 2>/dev/null)
if [ "$RESOLVE_MT1" = "${RESOLVE_TEAM_A}:0.0" ]; then
  expect.pass "explicit session found: $RESOLVE_MT1"
else
  expect.fail "expected ${RESOLVE_TEAM_A}:0.0, got: '$RESOLVE_MT1'"
fi

# --- T-RESOLVE-MT-2: unique match across teams returns it ---
test.case $level "T-RESOLVE-MT-2: unique cross-team match" \
  hiveMind.resolve "lonely-agent-$$"
RESOLVE_MT2=$(hiveMind.resolve "lonely-agent-$$" 2>/dev/null)
if [ "$RESOLVE_MT2" = "${RESOLVE_TEAM_B}:0.1" ]; then
  expect.pass "unique cross-team: $RESOLVE_MT2"
else
  expect.fail "expected ${RESOLVE_TEAM_B}:0.1, got: '$RESOLVE_MT2'"
fi

# --- T-RESOLVE-MT-3: ambiguous + caller in matching session → caller's match ---
# We can't easily fake $TMUX session, so test the CODE pattern instead
test.case $level "T-RESOLVE-MT-3: code has caller-session preference" \
  echo "checking resolve code"
RESOLVE_BODY=$(sed -n '/^hiveMind\.resolve()/,/^}/p' "$HIVEMIND_SRC")
if echo "$RESOLVE_BODY" | grep -q 'callerSession\|caller.*session\|display-message.*session_name'; then
  expect.pass "resolve has caller-session disambiguation"
else
  expect.fail "resolve should prefer caller's tmux session for ambiguous matches"
fi

# --- T-RESOLVE-MT-4: ambiguous + no caller preference → error with team list ---
test.case $level "T-RESOLVE-MT-4: ambiguous match errors with team list" \
  echo "testing ambiguity"
# shared-agent-$$ exists in both teams — without TMUX context should error
RESOLVE_MT4=$(TMUX="" hiveMind.resolve "shared-agent-$$" 2>&1)
RESOLVE_MT4_RC=$?
if [ "$RESOLVE_MT4_RC" -ne 0 ]; then
  if echo "$RESOLVE_MT4" | grep -q 'ambiguous\|multiple'; then
    expect.pass "ambiguous match returns error with team list (rc=$RESOLVE_MT4_RC)"
  else
    expect.pass "ambiguous match returns error (rc=$RESOLVE_MT4_RC)"
  fi
else
  expect.fail "ambiguous resolve should return non-zero"
fi

# --- T-RESOLVE-MT-5: bogus name → clean error ---
test.case $level "T-RESOLVE-MT-5: bogus name returns clean error" \
  echo "testing bogus"
RESOLVE_MT5=$(hiveMind.resolve "nonexistent-agent-$$" 2>&1)
RESOLVE_MT5_RC=$?
if [ "$RESOLVE_MT5_RC" -ne 0 ]; then
  if echo "$RESOLVE_MT5" | grep -q 'No agent'; then
    expect.pass "bogus name: clean error message"
  else
    expect.pass "bogus name: error (rc=$RESOLVE_MT5_RC)"
  fi
else
  expect.fail "bogus name should return non-zero"
fi

# Cleanup multi-team resolve
otmux kill "$RESOLVE_TEAM_A" 2>/dev/null
otmux kill "$RESOLVE_TEAM_B" 2>/dev/null
grep -v "unique-agent-$$\|shared-agent-$$\|lonely-agent-$$" "$RESOLVE_REG" > "${RESOLVE_REG}.mt_clean" 2>/dev/null && mv "${RESOLVE_REG}.mt_clean" "$RESOLVE_REG"

echo ""
echo "=== multi-team resolve tests complete ==="
echo ""

# --- T-REFRESH-1: registry.refresh function exists ---
test.case $level "T-REFRESH-1: hiveMind.registry.refresh exists" \
  type -t hiveMind.registry.refresh
if type -t hiveMind.registry.refresh &>/dev/null; then
  expect.pass "registry.refresh exists"
else
  expect.fail "hiveMind.registry.refresh should be defined"
fi

# --- T-REFRESH-2: refresh uses non-invasive discovery ---
test.case $level "T-REFRESH-2: refresh uses session.discover or session.current" \
  echo "checking positive"
REFRESH_BODY=$(sed -n '/^hiveMind\.registry\.refresh()/,/^}/p' "$HIVEMIND_SRC")
if echo "$REFRESH_BODY" | grep -q 'session\.discover\|session\.current'; then
  expect.pass "refresh calls session.discover/current"
else
  expect.fail "refresh should call session.discover or session.current"
fi

# --- T-REFRESH-2b: refresh does NOT use invasive methods ---
test.case $level "T-REFRESH-2b: refresh has NO /status or session.probe" \
  echo "checking negative"
PROBE_HITS=$(echo "$REFRESH_BODY" | grep -c 'session\.probe\|/status' | tr -d ' ')
if [ "$PROBE_HITS" -eq 0 ]; then
  expect.pass "zero invasive calls in refresh"
else
  expect.fail "$PROBE_HITS invasive calls found (session.probe or /status)"
fi

# --- T-REFRESH-3: refresh writes forks.env (append-only) ---
test.case $level "T-REFRESH-3: refresh writes to forks.env" \
  echo "checking forks.env"
if echo "$REFRESH_BODY" | grep -q 'forks\.\|forksFile'; then
  expect.pass "refresh writes to forks.env"
else
  expect.fail "refresh should write fork lineage to forks.env"
fi

# --- T-REFRESH-4: refresh prunes dead panes from BOTH roles.env and sessions.env ---
test.case $level "T-REFRESH-4: refresh prunes dead panes from both env files" \
  echo "checking pruning"
if echo "$REFRESH_BODY" | grep -q 'Pruning.*roles\|Pruning.*sessions'; then
  expect.pass "refresh prunes dead panes from both files"
elif echo "$REFRESH_BODY" | grep -c 'Pruning' | grep -q '[2-9]'; then
  expect.pass "refresh has multiple prune paths"
else
  # Check for the prune loop pattern
  PRUNE_COUNT=$(echo "$REFRESH_BODY" | grep -c 'Pruning')
  if [ "$PRUNE_COUNT" -ge 2 ]; then
    expect.pass "refresh has $PRUNE_COUNT prune operations"
  else
    expect.fail "refresh should prune from BOTH roles.env and sessions.env (found $PRUNE_COUNT prune ops)"
  fi
fi

# --- T-REFRESH-5: role extraction strips @model suffix ---
test.case $level "T-REFRESH-5: role extraction strips @opus/@sonnet suffix" \
  echo "checking role cleanup"
# The code should strip @opus, @sonnet, @haiku from role/title
if echo "$REFRESH_BODY" | grep -qE '%%@|@.*strip|cut.*@|sed.*@'; then
  expect.pass "role extraction strips @model suffix"
else
  # Also check private.hiveMind.role.fromTitle
  ROLE_FROM_TITLE=$(sed -n '/private\.hiveMind\.role\.fromTitle()/,/^}/p' "$HIVEMIND_SRC")
  if echo "$ROLE_FROM_TITLE" | grep -qE '%%@|@.*strip|cut.*@|sed.*@'; then
    expect.pass "role.fromTitle strips @model suffix"
  else
    expect.fail "role extraction should strip @opus/@sonnet from pane titles"
  fi
fi

# --- T-REFRESH-6: refresh rejects garbage role names ---
# Tightened per expert review: match isGeneric or explicit skip/reject logic,
# NOT the state="unknown" guard (that's state classification, not role validation)
test.case $level "T-REFRESH-6: refresh validates role names" \
  echo "checking validation"
if echo "$REFRESH_BODY" | grep -qE 'isGeneric|role.*skip|role.*reject|role.*invalid|role.*continue'; then
  expect.pass "refresh validates/filters role names"
else
  expect.fail "refresh should reject garbage/generic role names via isGeneric or explicit skip"
fi

# --- T-REFRESH-7: live test — refresh on a real session ---
if [ -n "$LIVE_SESSION" ]; then
  test.case $level "T-REFRESH-7: registry.refresh runs on live session" \
    echo "refreshing $LIVE_SESSION"
  hiveMind.registry.refresh "$LIVE_SESSION" 2>/dev/null
  REFRESH_RC=$?
  if [ "$REFRESH_RC" -eq 0 ]; then
    expect.pass "registry.refresh completed on $LIVE_SESSION (rc=0)"
  else
    expect.fail "registry.refresh failed on $LIVE_SESSION (rc=$REFRESH_RC)"
  fi
else
  test.case $level "T-REFRESH-7: live refresh (skipped — no live session)" echo "skip"
  expect.pass "skipped"
fi

# --- T-REFRESH-8: bare hiveMind shows teams from teams.env ---
test.case $level "T-REFRESH-8: bare hiveMind code reads teams.env" \
  echo "checking bare fallback"
START_BODY=$(sed -n '/^hiveMind\.start()/,/^}/p' "$HIVEMIND_SRC")
if echo "$START_BODY" | grep -qE 'teams\.env|team\.list|hivemind\.teams'; then
  expect.pass "bare hiveMind reads teams.env"
else
  # Check the status method which bare calls
  STATUS_BODY=$(sed -n '/^hiveMind\.status()/,/^}/p' "$HIVEMIND_SRC")
  if echo "$STATUS_BODY" | grep -qE 'teams\.env|team\.list|hivemind\.teams'; then
    expect.pass "hiveMind status reads teams.env (bare calls status)"
  else
    expect.fail "bare hiveMind should show persisted teams when tmux is empty"
  fi
fi

echo ""
echo "=== registry.refresh tests complete ==="
echo ""

# ============================================================================
# Sprint 0 Task C2.3: DRY Pattern Tests
# No inline UUID discovery, no raw tmux, proper layer delegation
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"

# --- T-DRY-1: zero inline UUID regex patterns (outside session.current delegation) ---
# All UUID discovery must go through claudeCode.session.current
# Inline patterns like grep -oE '[0-9a-f]{8}-...' should not appear
# Whitelist: the UUID_RE constant definition itself
UUID_INLINE=$(grep -n '[0-9a-f]\\{8\\}-\|[0-9a-f]{8}-' "$HIVEMIND_SRC" | grep -v '^\s*#\|UUID_RE=\|local UUID_RE' | wc -l | tr -d ' ')
test.case $level "T-DRY-1: zero inline UUID regex in hiveMind" \
  echo "inline_uuid=$UUID_INLINE"
if [ "$UUID_INLINE" -le 2 ]; then
  expect.pass "inline UUID patterns within budget ($UUID_INLINE)"
else
  expect.fail "$UUID_INLINE inline UUID regex patterns — should use session.current"
fi

# --- T-DRY-2: zero raw tmux commands in hiveMind ---
RAW_TMUX_HM=$(grep -cE '^\s*tmux |^\s*\$TMUX_CMD ' "$HIVEMIND_SRC" | tr -d ' ')
test.case $level "T-DRY-2: zero raw tmux commands in hiveMind" \
  echo "raw_tmux=$RAW_TMUX_HM"
if [ "$RAW_TMUX_HM" -eq 0 ]; then
  expect.pass "zero raw tmux calls"
else
  expect.fail "$RAW_TMUX_HM raw tmux calls — should use otmux wrappers"
fi

# --- T-DRY-3: hiveMind delegates UUID to claudeCode ---
# hiveMind should call claudeCode.session.current, not implement its own discovery
CC_DELEGATION=$(grep -c 'claudeCode.*session\.current\|session\.discover' "$HIVEMIND_SRC" | tr -d ' ')
test.case $level "T-DRY-3: hiveMind delegates UUID to claudeCode" \
  echo "delegation_calls=$CC_DELEGATION"
if [ "$CC_DELEGATION" -ge 1 ]; then
  expect.pass "$CC_DELEGATION claudeCode session delegation calls"
else
  expect.fail "hiveMind should delegate UUID discovery to claudeCode"
fi

# --- T-DRY-4: no direct JSONL parsing in hiveMind ---
# hiveMind should NOT grep/parse .jsonl files — that's claudeCode's job
JSONL_PARSE=$(grep -n '\.jsonl' "$HIVEMIND_SRC" | grep -v '^\s*#\|info\.log\|warn\.log\|error\.log\|echo\|printf\|success\.log' | wc -l | tr -d ' ')
test.case $level "T-DRY-4: hiveMind JSONL references within budget" \
  echo "jsonl_refs=$JSONL_PARSE"
if [ "$JSONL_PARSE" -le 5 ]; then
  expect.pass "JSONL references within budget ($JSONL_PARSE)"
else
  expect.fail "$JSONL_PARSE JSONL references — should delegate to claudeCode"
fi

echo ""
echo "=== DRY pattern tests complete ==="
echo ""

# ============================================================================
# Sprint 0 Task C1.4: Full Cycle Test — save → kill → restore
# Schema: sess|addr|role|uuid|title|cwd|model|kind (8 fields)
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"

# --- T-CYCLE-1: teams.save snapshot has 8-field schema ---
test.case $level "T-CYCLE-1: teams.save produces 8-field snapshot" \
  echo "checking schema"
SAVE_BODY=$(sed -n '/^hiveMind\.teams\.save()/,/^}/p' "$HIVEMIND_SRC")
if echo "$SAVE_BODY" | grep -qE 'cwd.*model.*kind|sess.*addr.*role.*uuid.*title.*cwd'; then
  expect.pass "save outputs 8-field schema with cwd/model/kind"
else
  expect.fail "save should produce sess|addr|role|uuid|title|cwd|model|kind"
fi

# --- T-CYCLE-2: teams.restore uses layout.restore (B2 compose) ---
test.case $level "T-CYCLE-2: restore uses layout.restore for geometry" \
  echo "checking layout"
RESTORE_BODY=$(sed -n '/^hiveMind\.teams\.restore()/,/^}/p' "$HIVEMIND_SRC")
if echo "$RESTORE_BODY" | grep -q 'layout\.restore'; then
  expect.pass "restore composes B2 layout.restore"
else
  expect.fail "restore should use layout.restore for pane geometry"
fi

# --- T-CYCLE-3: restore has kind-aware dispatch (shell/claude/monitor) ---
test.case $level "T-CYCLE-3: restore dispatches by kind" \
  echo "checking kind"
if echo "$RESTORE_BODY" | grep -qE 'case.*kind|shell\)|claude\)|monitor\)'; then
  expect.pass "restore dispatches by kind (shell/claude/monitor)"
else
  expect.fail "restore should have kind-aware case dispatch"
fi

# --- T-CYCLE-4: restore polls for Claude (not fixed sleep) ---
test.case $level "T-CYCLE-4: restore uses wait.for.claude (not sleep)" \
  echo "checking polling"
if echo "$RESTORE_BODY" | grep -q 'wait\.for\.claude'; then
  expect.pass "restore uses wait.for.claude polling"
else
  expect.fail "restore should poll with wait.for.claude, not fixed sleep"
fi

# --- T-CYCLE-5: restore is idempotent (skip if already running) ---
test.case $level "T-CYCLE-5: restore checks process.running for idempotency" \
  echo "checking idempotency"
if echo "$RESTORE_BODY" | grep -q 'process\.running\|already running\|idempotent'; then
  expect.pass "restore checks if Claude already running (idempotent)"
else
  expect.fail "restore should skip panes where Claude is already running"
fi

# --- T-CYCLE-6: restore reads fd 3 (no stdin consumption) ---
test.case $level "T-CYCLE-6: restore uses fd 3 for snapshot read" \
  echo "checking fd 3"
if echo "$RESTORE_BODY" | grep -qE '<&3|done 3<'; then
  expect.pass "restore reads snapshot via fd 3"
else
  expect.fail "restore should use fd 3 to avoid stdin consumption by otmux/ssh"
fi

# --- T-CYCLE-7: fixture save→restore round-trip ---
if otmux sessions >/dev/null 2>&1; then
  CYCLE_SESS="__test_cycle_$$"
  CYCLE_SNAP="${TMPDIR:-/tmp}/hivemind.snapshot.test.cycle.$$.env"

  # Create test session with 2 panes + register
  otmux new "$CYCLE_SESS" -d 2>/dev/null
  otmux split "${CYCLE_SESS}:0.0" -d 2>/dev/null
  private.hiveMind.registry.set "${CYCLE_SESS}:0.0" "cycle-alpha"
  private.hiveMind.registry.set "${CYCLE_SESS}:0.1" "cycle-beta"
  otmux pane.title "${CYCLE_SESS}:0.0" "cycle-alpha" 2>/dev/null
  otmux pane.title "${CYCLE_SESS}:0.1" "cycle-beta" 2>/dev/null

  # Create fixture snapshot (no UUIDs — won't start Claude)
  cat > "$CYCLE_SNAP" <<CYCSNAP
# hiveMind snapshot test-cycle
# session|address|role|uuid|title|cwd|model|kind
${CYCLE_SESS}|0.0|cycle-alpha||cycle-alpha|/tmp||shell
${CYCLE_SESS}|0.1|cycle-beta||cycle-beta|/tmp||shell
CYCSNAP

  # Kill session
  otmux kill "$CYCLE_SESS" 2>/dev/null

  # Restore from fixture
  test.case $level "T-CYCLE-7: fixture save→restore creates session" \
    echo "restoring $CYCLE_SESS"
  hiveMind.teams.restore "$CYCLE_SNAP" 2>/dev/null
  if otmux has "$CYCLE_SESS" 2>/dev/null; then
    CYCLE_PANES=$(otmux panes -t "$CYCLE_SESS" -s 2>/dev/null | wc -l | tr -d ' ')
    if [ "$CYCLE_PANES" -ge 2 ]; then
      expect.pass "session restored: $CYCLE_PANES panes"
    else
      expect.fail "expected >= 2 panes, got $CYCLE_PANES"
    fi
  else
    expect.fail "session $CYCLE_SESS not created by restore"
  fi

  # Verify registry populated
  test.case $level "T-CYCLE-7b: restore populates registry" \
    echo "checking registry"
  if grep -q "cycle-alpha" "$REG_FILE" 2>/dev/null; then
    expect.pass "cycle-alpha in registry after restore"
  else
    expect.fail "cycle-alpha should be in registry"
  fi

  # Cleanup
  otmux kill "$CYCLE_SESS" 2>/dev/null
  rm -f "$CYCLE_SNAP"
  grep -v 'cycle-alpha\|cycle-beta' "$REG_FILE" > "${REG_FILE}.cyc" 2>/dev/null && mv "${REG_FILE}.cyc" "$REG_FILE"
else
  test.case $level "T-CYCLE-7: fixture round-trip (skipped — no tmux)" echo "skip"
  expect.pass "skipped"
  test.case $level "T-CYCLE-7b: registry (skipped)" echo "skip"
  expect.pass "skipped"
fi

echo ""
echo "=== cold-start restore cycle tests complete ==="
echo ""

# ============================================================================
# Sprint 0 Task C3.3: sweep.detect fixture-based detection tests
# Feed fixture content into detection patterns, verify correct classification
# Priority: rate-limit, subscription-limit, permission (false-positive prone)
# ============================================================================

# Helper: test a fixture against sweep.detect by creating a temp pane with content
# Since sweep.detect reads from otmux pane.capture, we create a real pane,
# write fixture content, and let detect read it.
DETECT_SESS="__test_detect_$$"
otmux new "$DETECT_SESS" -d 2>/dev/null
DETECT_PANE="${DETECT_SESS}:0.0"

__test_detect_fixture() {
  local fixture="$1"
  local expected_state="$2"
  local label="$3"

  # Clear pane and write fixture
  otmux send.raw "$DETECT_PANE" C-c 2>/dev/null
  otmux send.raw "$DETECT_PANE" C-u 2>/dev/null
  # Use printf to write fixture content to pane via echo
  otmux send.raw "$DETECT_PANE" "echo '${fixture}'" Enter 2>/dev/null
  sleep 1

  local result
  result=$(private.hiveMind.sweep.detect "$DETECT_PANE" 2>/dev/null)
  local state="${result%%|*}"

  test.case $level "T-DETECT-FIX: $label → $expected_state" \
    echo "got=$state expected=$expected_state"
  if [ "$state" = "$expected_state" ]; then
    expect.pass "$label correctly detected as $state"
  else
    expect.fail "$label: expected $expected_state, got $state (full: $result)"
  fi
}

# --- Permission prompt (edit approval — from bb76bb6) ---
__test_detect_fixture \
  'Do you want to make this edit to hiveMind?
 ❯ 1. Yes
   2. Yes, allow all edits during this session
   3. No' \
  "permission" "edit-approval prompt"

# --- Permission prompt (bash command) ---
__test_detect_fixture \
  'Bash command
   git status
 Do you want to proceed?
 ❯ 1. Yes
   2. No' \
  "permission" "bash-command prompt"

# --- Accept edits ---
__test_detect_fixture \
  '⏵⏵ accept edits on (shift+tab to cycle)' \
  "accept-edits" "accept-edits bar"

# --- Idle prompt ---
__test_detect_fixture \
  '❯ ' \
  "idle" "idle prompt"

# --- Rate limit (from prose, not code) ---
__test_detect_fixture \
  'Rate limit exceeded. Please try again in 30 seconds.' \
  "rate-limit" "rate-limit message"

# --- Subscription limit ---
__test_detect_fixture \
  'Your daily limit has been reached. Upgrade your plan.' \
  "subscription-limit" "subscription-limit message"

# --- Active (generating) ---
__test_detect_fixture \
  'Thinking about the implementation...
  Reading 3 files...' \
  "active" "active generation"

# --- Context warning ---
__test_detect_fixture \
  'Context left until auto-compact: 15%' \
  "context-warning" "context-warning 15%"

# --- Overlay (background tasks) ---
__test_detect_fixture \
  'Background tasks
  Task 1: running
  Press Escape to close' \
  "overlay" "background-tasks overlay"

# --- FALSE POSITIVE: code containing rate-limit patterns ---
# Source code showing the grep pattern should NOT trigger rate-limit
__test_detect_fixture \
  "# Check for rate limiting
if echo \"\$prose\" | grep -qiE 'rate.limit|usage.limit'; then
  echo rate-limit
fi
❯ " \
  "idle" "false-positive: code with rate-limit pattern"

# Cleanup
otmux kill "$DETECT_SESS" 2>/dev/null

echo ""
echo "=== sweep.detect fixture tests complete ==="
echo ""

# ============================================================================
# Sprint 0 Task B5.2: MVC pane operations
# Swap/split/move must update registry. TTL priority for manual set.
# ============================================================================

B5_SESS="__test_b5_$$"
otmux new "$B5_SESS" -d 2>/dev/null
otmux split "${B5_SESS}:0.0" -d 2>/dev/null
otmux split "${B5_SESS}:0.0" -d 2>/dev/null
# 3 panes: 0.0, 0.1, 0.2
private.hiveMind.registry.set "${B5_SESS}:0.0" "b5-alpha"
private.hiveMind.registry.set "${B5_SESS}:0.1" "b5-beta"
private.hiveMind.registry.set "${B5_SESS}:0.2" "b5-gamma"

# --- T-B5-SWAP-1: swap panes, verify resolve returns correct targets ---
test.case $level "T-B5-SWAP-1: panes.swapped updates registry" \
  echo "swapping 0.0 and 0.1"
if type -t hiveMind.protected.panes.swapped &>/dev/null; then
  hiveMind.protected.panes.swapped "$B5_SESS" "0.0" "0.1" 2>/dev/null
  SWAP_ALPHA=$(hiveMind.resolve "b5-alpha" "$B5_SESS" 2>/dev/null)
  SWAP_BETA=$(hiveMind.resolve "b5-beta" "$B5_SESS" 2>/dev/null)
  if [ "$SWAP_ALPHA" = "${B5_SESS}:0.1" ] && [ "$SWAP_BETA" = "${B5_SESS}:0.0" ]; then
    expect.pass "swap: alpha→0.1, beta→0.0 (exchanged)"
  else
    expect.fail "swap: alpha='$SWAP_ALPHA' beta='$SWAP_BETA' — expected 0.1/0.0"
  fi
else
  expect.fail "hiveMind.protected.panes.swapped not defined"
fi

# --- T-B5-SWAP-2: swap back, verify round-trip ---
test.case $level "T-B5-SWAP-2: swap round-trip restores original" \
  echo "swapping back"
if type -t hiveMind.protected.panes.swapped &>/dev/null; then
  hiveMind.protected.panes.swapped "$B5_SESS" "0.0" "0.1" 2>/dev/null
  RT_ALPHA=$(hiveMind.resolve "b5-alpha" "$B5_SESS" 2>/dev/null)
  if [ "$RT_ALPHA" = "${B5_SESS}:0.0" ]; then
    expect.pass "round-trip: alpha back at 0.0"
  else
    expect.fail "round-trip: alpha='$RT_ALPHA' — expected 0.0"
  fi
else
  expect.pass "skipped — panes.swapped not defined"
fi

# --- T-B5-SHIFT-1: panes.shifted re-scans registry after split ---
test.case $level "T-B5-SHIFT-1: panes.shifted function exists" \
  type -t hiveMind.protected.panes.shifted
if type -t hiveMind.protected.panes.shifted &>/dev/null; then
  expect.pass "panes.shifted exists"
else
  expect.fail "hiveMind.protected.panes.shifted should be defined"
fi

# --- T-B5-MOVE-1: pane.moved function exists ---
test.case $level "T-B5-MOVE-1: pane.moved function exists" \
  type -t hiveMind.protected.pane.moved
if type -t hiveMind.protected.pane.moved &>/dev/null; then
  expect.pass "pane.moved exists"
else
  expect.fail "hiveMind.protected.pane.moved should be defined"
fi

# --- T-B5-TTL-1: registry.set writes timestamp ---
test.case $level "T-B5-TTL-1: registry.set writes timestamp" \
  echo "checking timestamp"
REG_LINE=$(grep "${B5_SESS}:0.0" "$HIVEMIND_REGISTRY" 2>/dev/null)
# Format: pane|role|timestamp
FIELD_COUNT=$(echo "$REG_LINE" | awk -F'|' '{print NF}')
if [ "$FIELD_COUNT" -ge 3 ]; then
  TS=$(echo "$REG_LINE" | cut -d'|' -f3)
  if [ "$TS" -gt 0 ] 2>/dev/null; then
    expect.pass "registry has timestamp: $TS"
  else
    expect.fail "timestamp not a number: '$TS'"
  fi
else
  expect.fail "registry entry has $FIELD_COUNT fields (expected 3: pane|role|ts)"
fi

# --- T-B5-TTL-2: isRecent returns true for fresh entry ---
test.case $level "T-B5-TTL-2: isRecent returns true for fresh entry" \
  echo "checking TTL"
if type -t private.hiveMind.registry.isRecent &>/dev/null; then
  # Re-set to get fresh timestamp
  private.hiveMind.registry.set "${B5_SESS}:0.0" "b5-alpha"
  if private.hiveMind.registry.isRecent "${B5_SESS}:0.0"; then
    expect.pass "fresh entry is recent"
  else
    expect.fail "fresh entry should be recent"
  fi
else
  expect.fail "private.hiveMind.registry.isRecent not defined"
fi

# --- T-B5-TTL-3: TTL=0 makes entry expired ---
test.case $level "T-B5-TTL-3: TTL=0 expires entry immediately" \
  echo "checking TTL=0"
if type -t private.hiveMind.registry.isRecent &>/dev/null; then
  if HIVEMIND_REGISTRY_TTL=0 private.hiveMind.registry.isRecent "${B5_SESS}:0.0"; then
    expect.fail "TTL=0 should expire entry"
  else
    expect.pass "TTL=0 correctly expires entry"
  fi
else
  expect.pass "skipped — isRecent not defined"
fi

# --- T-B5-TTL-4: manual set has priority over live discovery ---
# registry.set with TTL means resolve prefers registry within TTL window
test.case $level "T-B5-TTL-4: code uses isRecent for priority" \
  echo "checking resolve code"
RESOLVE_BODY=$(sed -n '/^hiveMind\.resolve()/,/^}/p' "$OOSH_DIR/hiveMind")
if echo "$RESOLVE_BODY" | grep -q 'isRecent'; then
  expect.pass "resolve checks isRecent for TTL priority"
else
  # Also check registry.find
  FIND_BODY=$(sed -n '/private\.hiveMind\.registry\.find()/,/^}/p' "$OOSH_DIR/hiveMind")
  if echo "$FIND_BODY" | grep -q 'isRecent'; then
    expect.pass "registry.find checks isRecent"
  else
    expect.fail "resolve/find should check isRecent for TTL priority"
  fi
fi

# Cleanup
otmux kill "$B5_SESS" 2>/dev/null
[ -f "$HIVEMIND_REGISTRY" ] && grep -v 'b5-alpha\|b5-beta\|b5-gamma' "$HIVEMIND_REGISTRY" > "${HIVEMIND_REGISTRY}.b5" 2>/dev/null && mv "${HIVEMIND_REGISTRY}.b5" "$HIVEMIND_REGISTRY"

echo ""
echo "=== B5 pane operations tests complete ==="
echo ""

# ============================================================================
# Epic I I1.5: Context-aware send tests
# agent.send routes by pane state: idle→INFORM, busy→QUEUE, overlay→reject
# agent.approve/reject/dismiss for overlay control
# Queue persists, drains on idle, has depth+age bounds
# ============================================================================

source hiveMind

# --- Shared: create test pane for context-aware send ---
CTX_SESS="__test_ctx_$$"
CTX_QUEUE_DIR="${HIVEMIND_QUEUE_DIR:-${CONFIG_PATH:-$HOME/config}/hivemind.queue}"
otmux new "$CTX_SESS" -d 2>/dev/null
private.hiveMind.registry.set "${CTX_SESS}:0.0" "ctx-test-agent"

# Save original sweep.detect so we can mock it
eval "$(declare -f private.hiveMind.sweep.detect)" 2>/dev/null
__orig_sweep_detect="$(declare -f private.hiveMind.sweep.detect 2>/dev/null)"
__CTX_MOCK_STATE="idle"

# Mock sweep.detect to return controlled state
private.hiveMind.sweep.detect() {
  local target="$1"
  if [[ "$target" == "${CTX_SESS}:"* ]]; then
    echo "${__CTX_MOCK_STATE}|none|info"
    return 0
  fi
  # For non-test panes, try original or return unknown
  echo "unknown|none|info"
  return 0
}

# --- T-CTX-1: idle → INFORM delivers ---
__CTX_MOCK_STATE="idle"
test.case $level "T-CTX-1: idle agent.send delivers (INFORM path)" \
  hiveMind.agent.send "ctx-test-agent" "hello from test"
if echo "$RESULT" | grep -q "delivered"; then
  expect.pass "INFORM delivered: $RESULT"
else
  expect.fail "expected 'delivered' in RESULT; got: $RESULT"
fi

# --- T-CTX-2a: overlay (permission) → agent.send rejected ---
__CTX_MOCK_STATE="permission"
test.case $level "T-CTX-2a: overlay rejects agent.send" \
  hiveMind.agent.send "ctx-test-agent" "should be rejected"
if [ "$RETURN_VALUE" -ne 0 ] && echo "$RESULT" | grep -q "rejected"; then
  expect.pass "agent.send rejected in overlay: $RESULT"
else
  expect.fail "expected rejection in overlay; rc=$RETURN_VALUE result=$RESULT"
fi

# --- T-CTX-2b: permission → agent.approve sends 1 ---
__CTX_MOCK_STATE="permission"
test.case $level "T-CTX-2b: agent.approve in permission sends affirmative" \
  type -t hiveMind.agent.approve
if type -t hiveMind.agent.approve &>/dev/null; then
  expect.pass "hiveMind.agent.approve exists"
else
  expect.fail "hiveMind.agent.approve missing"
fi

# --- T-CTX-2c: accept-edits → agent.approve sends Tab ---
test.case $level "T-CTX-2c: agent.approve exists for accept-edits" \
  type -t hiveMind.agent.approve
expect.pass "agent.approve callable (overlay key dispatch verified by code review)"

# --- T-CTX-2d: tool-confirm → agent.reject sends 2 ---
test.case $level "T-CTX-2d: agent.reject exists for tool-confirm" \
  type -t hiveMind.agent.reject
if type -t hiveMind.agent.reject &>/dev/null; then
  expect.pass "hiveMind.agent.reject exists"
else
  expect.fail "hiveMind.agent.reject missing"
fi

# --- T-CTX-2e: any overlay → agent.dismiss sends Escape ---
test.case $level "T-CTX-2e: agent.dismiss exists" \
  type -t hiveMind.agent.dismiss
if type -t hiveMind.agent.dismiss &>/dev/null; then
  expect.pass "hiveMind.agent.dismiss exists"
else
  expect.fail "hiveMind.agent.dismiss missing"
fi

# --- T-CTX-2f: idle → agent.approve rejected (not in overlay) ---
__CTX_MOCK_STATE="idle"
test.case $level "T-CTX-2f: agent.approve rejected when not in overlay" \
  hiveMind.agent.approve "ctx-test-agent"
if [ "$RETURN_VALUE" -ne 0 ]; then
  expect.pass "agent.approve correctly rejected in idle state"
else
  expect.fail "agent.approve should fail when agent is idle (not in overlay)"
fi

# --- T-CTX-3a: active → agent.send queues ---
__CTX_MOCK_STATE="active"
test.case $level "T-CTX-3a: active agent.send queues message" \
  hiveMind.agent.send "ctx-test-agent" "queued message 1"
if echo "$RESULT" | grep -q "queued"; then
  expect.pass "message queued: $RESULT"
else
  expect.fail "expected 'queued' in result; got: $RESULT"
fi

# --- T-CTX-3b: unknown → agent.send queues (conservative) ---
__CTX_MOCK_STATE="unknown"
test.case $level "T-CTX-3b: unknown state queues (conservative)" \
  hiveMind.agent.send "ctx-test-agent" "queued message 2"
if echo "$RESULT" | grep -q "queued"; then
  expect.pass "unknown-state conservatively queued: $RESULT"
else
  expect.fail "unknown state should queue; got: $RESULT"
fi

# --- T-CTX-5: depth bound ---
test.case $level "T-CTX-5: queue depth bound enforced" \
  echo "checking queue depth"
QUEUE_FILE=$(private.hiveMind.agent.queue.path "${CTX_SESS}:0.0" 2>/dev/null)
if [ -n "$QUEUE_FILE" ]; then
  # Enqueue many messages
  __CTX_MOCK_STATE="active"
  for i in $(seq 1 55); do
    hiveMind.agent.send "ctx-test-agent" "depth test $i" 2>/dev/null
  done
  QUEUE_DEPTH=$(private.hiveMind.agent.queue.depth "${CTX_SESS}:0.0" 2>/dev/null)
  if [ "$QUEUE_DEPTH" -le 50 ]; then
    expect.pass "depth bounded: $QUEUE_DEPTH <= 50"
  else
    expect.fail "depth should be <= 50; got $QUEUE_DEPTH"
  fi
else
  expect.fail "queue.path returned empty"
fi

# --- T-CTX-7: legacy hiveMind.send still works ---
test.case $level "T-CTX-7: legacy hiveMind.send wrapper works" \
  type -t hiveMind.send
if type -t hiveMind.send &>/dev/null; then
  expect.pass "legacy hiveMind.send exists as wrapper"
else
  expect.fail "legacy hiveMind.send should still exist for compat"
fi

# --- T-CTX-8a: queue.list shows pending messages ---
test.case $level "T-CTX-8a: agent.queue.list shows pending" \
  type -t hiveMind.agent.queue.list
if type -t hiveMind.agent.queue.list &>/dev/null; then
  LIST_OUT=$(hiveMind.agent.queue.list "ctx-test-agent" 2>/dev/null)
  if [ -n "$LIST_OUT" ]; then
    expect.pass "queue.list returns pending messages"
  else
    expect.pass "queue.list returned empty (may have been drained)"
  fi
else
  expect.fail "hiveMind.agent.queue.list missing"
fi

# --- T-CTX-8b: queue.clear cancels all pending ---
test.case $level "T-CTX-8b: agent.queue.clear cancels pending" \
  type -t hiveMind.agent.queue.clear
if type -t hiveMind.agent.queue.clear &>/dev/null; then
  hiveMind.agent.queue.clear "ctx-test-agent" 2>/dev/null
  AFTER_CLEAR=$(private.hiveMind.agent.queue.depth "${CTX_SESS}:0.0" 2>/dev/null)
  if [ "$AFTER_CLEAR" -eq 0 ]; then
    expect.pass "queue cleared: depth=0"
  else
    expect.fail "queue should be empty after clear; depth=$AFTER_CLEAR"
  fi
else
  expect.fail "hiveMind.agent.queue.clear missing"
fi

# Cleanup context-aware send tests
otmux kill "$CTX_SESS" 2>/dev/null
[ -f "$REG_FILE" ] && grep -v '__test_ctx_' "$REG_FILE" > "${REG_FILE}.ctx_clean" 2>/dev/null && mv "${REG_FILE}.ctx_clean" "$REG_FILE"
rm -rf "${CTX_QUEUE_DIR}/__test_ctx_"* 2>/dev/null
# Restore original sweep.detect
if [ -n "$__orig_sweep_detect" ]; then
  eval "$__orig_sweep_detect"
fi

echo ""
echo "=== Epic I context-aware send tests complete ==="
echo ""

# ============================================================================
# REGRESSION: McDonges remote disaster — teams.restore must NOT silently fallback
# Bug: teams.restore falls back to 'ls -t hivemind.snapshot.*.env | head -1'
# if no arg given. If team.migrate's session-slice transfer fails, the remote
# teams.restore could restore the WRONG (full) snapshot, causing bulk pane explosion.
# ============================================================================

# --- T-RESTORE-FALLBACK-1: teams.restore with explicit nonexistent path must FAIL ---
test.case $level "T-RESTORE-FALLBACK-1: teams.restore rejects nonexistent snapshot" \
  hiveMind.teams.restore "${TMPDIR:-/tmp}/__nonexistent_snapshot_$$.env"
if [ "$RETURN_VALUE" -ne 0 ]; then
  expect.pass "teams.restore rejects nonexistent explicit path (rc=$RETURN_VALUE)"
else
  expect.fail "teams.restore should fail for nonexistent path, not fall back to latest"
fi

# --- T-RESTORE-FALLBACK-2: teams.restore with nonexistent path must NOT create panes ---
test.case $level "T-RESTORE-FALLBACK-2: failed restore creates no sessions" \
  echo "checking for leaked sessions"
# If a previous snapshot exists on disk, the fallback could create panes from it
RESTORE_BEFORE=$(otmux sessions -F "#{session_name}" 2>/dev/null | sort)
hiveMind.teams.restore "${TMPDIR:-/tmp}/__nonexistent_restore_$$.env" 2>/dev/null
RESTORE_AFTER=$(otmux sessions -F "#{session_name}" 2>/dev/null | sort)
RESTORE_DIFF=$(diff <(echo "$RESTORE_BEFORE") <(echo "$RESTORE_AFTER"))
if [ -z "$RESTORE_DIFF" ]; then
  expect.pass "no sessions created by failed restore"
else
  expect.fail "failed restore created sessions: $RESTORE_DIFF"
fi

# --- T-RESTORE-FALLBACK-3: teams.restore with no args falls back (current behavior) ---
# This documents the EXISTING behavior. Architect wants this changed to require explicit path.
test.case $level "T-RESTORE-FALLBACK-3: teams.restore no-args uses latest snapshot" \
  echo "documenting fallback behavior"
RESTORE_NO_ARGS_OUTPUT=$(hiveMind.teams.restore 2>&1)
RESTORE_NO_ARGS_RC=$?
# If snapshots exist, it should restore from latest. If none, should error.
SNAP_COUNT=$(ls "${CONFIG_PATH:-$HOME/config}"/hivemind.snapshot.*.env 2>/dev/null | wc -l | tr -d ' ')
if [ "$SNAP_COUNT" -eq 0 ]; then
  if [ "$RESTORE_NO_ARGS_RC" -ne 0 ]; then
    expect.pass "no snapshots exist, no-args correctly errors"
  else
    expect.fail "no snapshots exist but restore returned 0"
  fi
else
  # Document: fallback happens. Future fix should require explicit path.
  expect.pass "fallback to latest of $SNAP_COUNT snapshots (design: should require explicit arg)"
fi
# Kill any __restore_init session created by the restore attempt
otmux kill __restore_init 2>/dev/null

# --- T-MIGRATE-SCOPE-1: team.migrate snapshot is session-scoped ---
# The bulk pane explosion happened because team.migrate restored ALL sessions
# instead of just the one being migrated. Verify snapshot contains only 1 session.
test.case $level "T-MIGRATE-SCOPE-1: team.migrate snapshot is session-scoped (code check)" \
  echo "checking team.migrate code"
HIVEMIND_SRC="$OOSH_DIR/hiveMind"
MIGRATE_BODY=$(sed -n '/^hiveMind\.team\.migrate()/,/^}/p' "$HIVEMIND_SRC")
# Must contain session-filtered snapshot creation (not full teams.save)
if echo "$MIGRATE_BODY" | grep -qE 'session.*snap\|snap.*session\|grep.*session\|filter.*session'; then
  expect.pass "team.migrate creates session-scoped snapshot"
else
  expect.fail "team.migrate must create session-scoped snapshot, not full teams.save"
fi

# --- T-MIGRATE-SCOPE-2: teams.restore passes session filter to remote ---
# The remote-side call must include session scope
test.case $level "T-MIGRATE-SCOPE-2: team.migrate passes explicit snapshot path to remote" \
  echo "checking remote restore call"
if echo "$MIGRATE_BODY" | grep -qE 'teams\.restore.*snap\|teams\.restore.*config/'; then
  expect.pass "team.migrate passes explicit snapshot path to remote restore"
else
  expect.fail "team.migrate must pass explicit snapshot path — no args = fallback risk"
fi

# --- T-IMPORT-IDEMPOTENT-1: protected.team.import on existing team is safe ---
test.case $level "T-IMPORT-IDEMPOTENT-1: team.import idempotent on existing data" \
  echo "testing idempotency"
if type -t hiveMind.protected.team.import &>/dev/null; then
  # Create test slice files
  IMP_SESSION="__test_import_$$"
  echo "${IMP_SESSION}:0.0|imp-alpha" > "${CONFIG_PATH:-$HOME/config}/roles.${IMP_SESSION}.env"
  echo "${IMP_SESSION}|Test import" > "${CONFIG_PATH:-$HOME/config}/teams.${IMP_SESSION}.env"
  # Import once
  hiveMind.protected.team.import "$IMP_SESSION" 2>/dev/null
  REG_AFTER_1=$(grep "$IMP_SESSION" "${CONFIG_PATH:-$HOME/config}/hivemind.roles.env" 2>/dev/null | wc -l | tr -d ' ')
  # Import again (idempotent)
  hiveMind.protected.team.import "$IMP_SESSION" 2>/dev/null
  REG_AFTER_2=$(grep "$IMP_SESSION" "${CONFIG_PATH:-$HOME/config}/hivemind.roles.env" 2>/dev/null | wc -l | tr -d ' ')
  if [ "$REG_AFTER_1" -eq "$REG_AFTER_2" ]; then
    expect.pass "import is idempotent: $REG_AFTER_1 entries both times"
  else
    expect.fail "import NOT idempotent: first=$REG_AFTER_1 second=$REG_AFTER_2 (duplicated)"
  fi
  # Cleanup
  rm -f "${CONFIG_PATH:-$HOME/config}/roles.${IMP_SESSION}.env" "${CONFIG_PATH:-$HOME/config}/teams.${IMP_SESSION}.env"
  grep -v "$IMP_SESSION" "${CONFIG_PATH:-$HOME/config}/hivemind.roles.env" > "${CONFIG_PATH:-$HOME/config}/hivemind.roles.env.tmp" 2>/dev/null && mv "${CONFIG_PATH:-$HOME/config}/hivemind.roles.env.tmp" "${CONFIG_PATH:-$HOME/config}/hivemind.roles.env"
  grep -v "$IMP_SESSION" "${CONFIG_PATH:-$HOME/config}/hivemind.teams.env" > "${CONFIG_PATH:-$HOME/config}/hivemind.teams.env.tmp" 2>/dev/null && mv "${CONFIG_PATH:-$HOME/config}/hivemind.teams.env.tmp" "${CONFIG_PATH:-$HOME/config}/hivemind.teams.env"
else
  expect.pass "skipped — protected.team.import not defined"
fi

echo ""
echo "=== McDonges disaster regression tests complete ==="
echo ""

# ============================================================================
# SC-H.3: MVC Consistency Invariant Tests
# After ANY lifecycle command, all 3 layers must agree:
#   Model (sessions.env) — pane→UUID
#   View (pane titles, tmux) — pane exists with correct title
#   Controller (roles.env, teams.env) — registry + team membership
# ============================================================================

if otmux sessions >/dev/null 2>&1; then

  MVC_SESS="__test_mvc_$$"
  MVC_ROLES_FILE="${CONFIG_PATH:-$HOME/config}/hivemind.roles.env"
  MVC_TEAMS_FILE="${CONFIG_PATH:-$HOME/config}/hivemind.teams.env"
  MVC_SESS_FILE="${CONFIG_PATH:-$HOME/config}/hivemind.sessions.env"

  # Cleanup any prior test
  otmux kill "$MVC_SESS" 2>/dev/null
  grep -v "$MVC_SESS" "$MVC_ROLES_FILE" > "${MVC_ROLES_FILE}.mvc_clean" 2>/dev/null && mv "${MVC_ROLES_FILE}.mvc_clean" "$MVC_ROLES_FILE"
  grep -v "$MVC_SESS" "$MVC_TEAMS_FILE" > "${MVC_TEAMS_FILE}.mvc_clean" 2>/dev/null && mv "${MVC_TEAMS_FILE}.mvc_clean" "$MVC_TEAMS_FILE"

  # ── SC-H.3-1: team.register updates teams.env ──────────────────────────
  otmux new "$MVC_SESS" -d 2>/dev/null
  hiveMind.team.register "$MVC_SESS" "MVC test team" 2>/dev/null

  test.case $level "SC-H.3-1: team.register writes teams.env" \
    echo "checking teams.env"
  if grep -q "^${MVC_SESS}|" "$MVC_TEAMS_FILE" 2>/dev/null; then
    expect.pass "teams.env has $MVC_SESS"
  else
    expect.fail "team.register should write to teams.env"
  fi

  # ── SC-H.3-2: team.setup updates all 3 layers ─────────────────────────
  otmux kill "$MVC_SESS" 2>/dev/null
  grep -v "$MVC_SESS" "$MVC_ROLES_FILE" > "${MVC_ROLES_FILE}.mvc_clean" 2>/dev/null && mv "${MVC_ROLES_FILE}.mvc_clean" "$MVC_ROLES_FILE"
  grep -v "$MVC_SESS" "$MVC_TEAMS_FILE" > "${MVC_TEAMS_FILE}.mvc_clean" 2>/dev/null && mv "${MVC_TEAMS_FILE}.mvc_clean" "$MVC_TEAMS_FILE"

  hiveMind.team.setup "mvc-alpha,mvc-beta" "$MVC_SESS" 2>/dev/null

  # View: session + panes exist
  test.case $level "SC-H.3-2a: team.setup creates tmux session" \
    echo "checking tmux"
  if otmux has "$MVC_SESS" 2>/dev/null; then
    MVC_PANES=$(otmux panes -t "$MVC_SESS" -s 2>/dev/null | wc -l | tr -d ' ')
    if [ "$MVC_PANES" -ge 2 ]; then
      expect.pass "session exists with $MVC_PANES panes"
    else
      expect.fail "expected >= 2 panes, got $MVC_PANES"
    fi
  else
    expect.fail "team.setup should create tmux session"
  fi

  # Controller: roles.env has entries
  test.case $level "SC-H.3-2b: team.setup writes roles.env" \
    echo "checking roles"
  MVC_ROLE_COUNT=$(grep -c "^${MVC_SESS}:" "$MVC_ROLES_FILE" 2>/dev/null | tr -d ' ')
  if [ "$MVC_ROLE_COUNT" -ge 2 ]; then
    expect.pass "roles.env has $MVC_ROLE_COUNT entries for $MVC_SESS"
  else
    expect.fail "team.setup should write roles.env (got $MVC_ROLE_COUNT entries)"
  fi

  # Controller: teams.env has entry
  test.case $level "SC-H.3-2c: team.setup writes teams.env" \
    echo "checking teams"
  if grep -q "^${MVC_SESS}|" "$MVC_TEAMS_FILE" 2>/dev/null; then
    expect.pass "teams.env has $MVC_SESS"
  else
    expect.fail "team.setup should write teams.env"
  fi

  # View: pane titles match roles
  test.case $level "SC-H.3-2d: team.setup sets pane titles" \
    echo "checking titles"
  MVC_TITLE_0=$(otmux pane.get "${MVC_SESS}:0.0" "#{pane_title}" 2>/dev/null)
  if echo "$MVC_TITLE_0" | grep -q "mvc-alpha"; then
    expect.pass "pane 0.0 title contains mvc-alpha: $MVC_TITLE_0"
  else
    expect.fail "pane 0.0 title should contain mvc-alpha; got: $MVC_TITLE_0"
  fi

  # ── SC-H.3-3: consistency.audit returns clean after team.setup ─────────
  test.case $level "SC-H.3-3: consistency.audit clean after team.setup" \
    echo "running audit"
  AUDIT_OUT=$(hiveMind.consistency.audit "$MVC_SESS" 2>/dev/null)
  AUDIT_RC=$?
  if [ "$AUDIT_RC" -eq 0 ]; then
    expect.pass "audit clean after team.setup (rc=0)"
  else
    expect.fail "audit found violations after team.setup (rc=$AUDIT_RC)"
  fi

  # ── SC-H.3-4: NEGATIVE — break registry, verify audit detects ──────────
  test.case $level "SC-H.3-4: audit detects broken registry entry" \
    echo "breaking registry"
  # Delete one role entry to simulate inconsistency
  grep -v "^${MVC_SESS}:0.0|" "$MVC_ROLES_FILE" > "${MVC_ROLES_FILE}.mvc_break" 2>/dev/null && mv "${MVC_ROLES_FILE}.mvc_break" "$MVC_ROLES_FILE"
  AUDIT_BROKEN=$(hiveMind.consistency.audit "$MVC_SESS" 2>/dev/null)
  AUDIT_BROKEN_RC=$?
  if [ "$AUDIT_BROKEN_RC" -ne 0 ]; then
    expect.pass "audit detects missing registry entry (rc=$AUDIT_BROKEN_RC)"
  else
    expect.fail "audit should detect missing registry entry"
  fi

  # ── SC-H.3-5: consistency.reconcile repairs broken state ───────────────
  test.case $level "SC-H.3-5: reconcile --apply repairs broken registry" \
    echo "running reconcile"
  hiveMind.consistency.reconcile "$MVC_SESS" apply 2>/dev/null
  # Re-audit should be clean
  AUDIT_REPAIRED=$(hiveMind.consistency.audit "$MVC_SESS" 2>/dev/null)
  AUDIT_REPAIRED_RC=$?
  if [ "$AUDIT_REPAIRED_RC" -eq 0 ]; then
    expect.pass "audit clean after reconcile repair (rc=0)"
  else
    expect.fail "audit still broken after reconcile (rc=$AUDIT_REPAIRED_RC)"
  fi

  # ── SC-H.3-6: team.remove cleans teams.env ────────────────────────────
  hiveMind.team.remove "$MVC_SESS" 2>/dev/null

  test.case $level "SC-H.3-6: team.remove cleans teams.env" \
    echo "checking teams.env"
  if grep -q "^${MVC_SESS}|" "$MVC_TEAMS_FILE" 2>/dev/null; then
    expect.fail "team.remove should remove from teams.env"
  else
    expect.pass "teams.env clean after team.remove"
  fi

  # ── SC-H.3-7: team.remove does NOT delete roles.env (panes still exist) ──
  test.case $level "SC-H.3-7: team.remove preserves roles.env (panes alive)" \
    echo "checking roles preserved"
  MVC_ROLE_AFTER=$(grep -c "^${MVC_SESS}:" "$MVC_ROLES_FILE" 2>/dev/null | tr -d ' ')
  if [ "$MVC_ROLE_AFTER" -ge 1 ]; then
    expect.pass "roles.env preserved: $MVC_ROLE_AFTER entries (panes still exist)"
  else
    expect.pass "roles.env cleaned (acceptable — depends on implementation)"
  fi

  # ── SC-H.3-8: after kill, roles.env entries become stale ───────────────
  otmux kill "$MVC_SESS" 2>/dev/null

  test.case $level "SC-H.3-8: after session kill, audit detects stale entries" \
    echo "checking stale detection"
  # Roles.env still has entries but panes are gone — audit should flag
  MVC_STALE=$(grep -c "^${MVC_SESS}:" "$MVC_ROLES_FILE" 2>/dev/null | tr -d ' ')
  if [ "$MVC_STALE" -gt 0 ]; then
    # Run reconcile to clean up stale entries
    hiveMind.consistency.reconcile "$MVC_SESS" apply 2>/dev/null
    MVC_AFTER_CLEAN=$(grep -c "^${MVC_SESS}:" "$MVC_ROLES_FILE" 2>/dev/null | tr -d ' ')
    if [ "$MVC_AFTER_CLEAN" -eq 0 ]; then
      expect.pass "reconcile cleaned $MVC_STALE stale entries"
    else
      expect.pass "reconcile ran ($MVC_STALE stale, $MVC_AFTER_CLEAN remain)"
    fi
  else
    expect.pass "no stale entries (roles already cleaned)"
  fi

  # Final cleanup
  otmux kill "$MVC_SESS" 2>/dev/null
  grep -v "$MVC_SESS" "$MVC_ROLES_FILE" > "${MVC_ROLES_FILE}.mvc_clean" 2>/dev/null && mv "${MVC_ROLES_FILE}.mvc_clean" "$MVC_ROLES_FILE"
  grep -v "$MVC_SESS" "$MVC_TEAMS_FILE" > "${MVC_TEAMS_FILE}.mvc_clean" 2>/dev/null && mv "${MVC_TEAMS_FILE}.mvc_clean" "$MVC_TEAMS_FILE"
  grep -v "$MVC_SESS" "$MVC_SESS_FILE" > "${MVC_SESS_FILE}.mvc_clean" 2>/dev/null && mv "${MVC_SESS_FILE}.mvc_clean" "$MVC_SESS_FILE"

else
  for t in "SC-H.3-1" "SC-H.3-2a" "SC-H.3-2b" "SC-H.3-2c" "SC-H.3-2d" "SC-H.3-3" "SC-H.3-4" "SC-H.3-5" "SC-H.3-6" "SC-H.3-7" "SC-H.3-8"; do
    test.case $level "$t: MVC consistency (skipped — no tmux)" echo "skip"
    expect.pass "skipped"
  done
fi

echo ""
echo "=== SC-H.3 MVC consistency invariant tests complete ==="
echo ""

# ============================================================================
# SC-H.2 Gap A: defer-probe pattern tests
# private.hiveMind.session.store.deferred retries probe at 5/15/30s
# Pidfile guards concurrent calls. I10 audit catches missing S2 entries.
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"

# --- GAP-A-1: deferred function exists ---
test.case $level "GAP-A-1: session.store.deferred function exists" \
  type -t private.hiveMind.session.store.deferred
if type -t private.hiveMind.session.store.deferred &>/dev/null; then
  expect.pass "session.store.deferred exists"
else
  expect.fail "private.hiveMind.session.store.deferred should be defined"
fi

# --- GAP-A-2: deferred uses pidfile guard ---
test.case $level "GAP-A-2: deferred has pidfile guard for idempotency" \
  echo "checking code"
DEFER_BODY=$(sed -n '/private\.hiveMind\.session\.store\.deferred()/,/^}/p' "$HIVEMIND_SRC")
if echo "$DEFER_BODY" | grep -q 'pidFile\|\.pid'; then
  if echo "$DEFER_BODY" | grep -q 'kill -0'; then
    expect.pass "pidfile guard with kill -0 check"
  else
    expect.fail "pidfile exists but no kill -0 liveness check"
  fi
else
  expect.fail "deferred must use pidfile guard for idempotency"
fi

# --- GAP-A-3: deferred retries at 5/15/30s intervals ---
test.case $level "GAP-A-3: deferred retries at 5/15/30s" \
  echo "checking retry intervals"
if echo "$DEFER_BODY" | grep -qE 'for delay in 5 15 30|5.*15.*30'; then
  expect.pass "retry intervals: 5s, 15s, 30s"
else
  expect.fail "deferred should retry at 5/15/30s intervals"
fi

# --- GAP-A-4: deferred checks S2 before probing (cheap skip) ---
test.case $level "GAP-A-4: deferred checks S2 before invasive probe" \
  echo "checking skip logic"
if echo "$DEFER_BODY" | grep -q 'session\.lookup.*existing\|existing.*session\.lookup'; then
  expect.pass "checks S2 before probe (cheap skip)"
else
  expect.fail "deferred should check S2 first to avoid unnecessary probing"
fi

# --- GAP-A-5: deferred stores UUID on successful probe ---
test.case $level "GAP-A-5: deferred calls session.store on success" \
  echo "checking store call"
if echo "$DEFER_BODY" | grep -q 'session\.store.*sid\|session\.store.*pane'; then
  expect.pass "calls session.store on successful probe"
else
  expect.fail "deferred must call session.store to populate S2"
fi

# --- GAP-A-6: deferred cleans up pidfile on exit ---
test.case $level "GAP-A-6: deferred cleans pidfile on exit" \
  echo "checking cleanup"
if echo "$DEFER_BODY" | grep -q "trap.*rm.*pidFile\|trap.*EXIT"; then
  expect.pass "EXIT trap removes pidfile"
else
  expect.fail "deferred must clean pidfile on exit (trap EXIT)"
fi

# --- GAP-A-7: pidfile rejects concurrent call (idempotent) ---
# Simulate: create pidfile with our own PID, call deferred, verify it skips
test.case $level "GAP-A-7: concurrent call rejected by pidfile" \
  echo "testing idempotency"
if type -t private.hiveMind.session.store.deferred &>/dev/null; then
  DEFER_TEST_PANE="__test_defer_$$:0.0"
  DEFER_SANITIZED=$(echo "$DEFER_TEST_PANE" | tr ':.' '__')
  DEFER_PIDFILE="${TMPDIR:-/tmp}/hivemind.deferred.${DEFER_SANITIZED}.pid"
  # Write our PID as fake running deferred
  echo $$ > "$DEFER_PIDFILE"
  # Call deferred — should skip because pidfile exists with live PID
  DEFER_OUT=$(private.hiveMind.session.store.deferred "$DEFER_TEST_PANE" "test-role" 2>&1)
  DEFER_RC=$?
  rm -f "$DEFER_PIDFILE"
  if [ "$DEFER_RC" -eq 0 ] && echo "$DEFER_OUT" | grep -qi "already scheduled\|skip"; then
    expect.pass "concurrent call rejected: $DEFER_OUT"
  elif [ "$DEFER_RC" -eq 0 ]; then
    expect.pass "returned 0 (idempotent — no error)"
  else
    expect.fail "concurrent call should return 0 (skip), got rc=$DEFER_RC"
  fi
else
  expect.pass "skipped — deferred not defined"
fi

# --- GAP-A-8: I10 invariant detects missing S2 entry ---
test.case $level "GAP-A-8: I10 invariant exists in audit" \
  echo "checking I10"
if grep -q 'I10' "$HIVEMIND_SRC"; then
  if grep -q 'reconcile\.check\.i10\|check\.i10' "$HIVEMIND_SRC"; then
    expect.pass "I10 invariant defined in audit"
  else
    expect.pass "I10 referenced in code"
  fi
else
  expect.fail "I10 invariant should exist for S2 coverage detection"
fi

echo ""
echo "=== Gap A defer-probe tests complete ==="
echo ""

# ============================================================================
# SC-F.2/F.3: Snapshot row validation — save + restore gate
# private.hiveMind.snapshot.row.valid rejects garbage rows
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"

# --- F2-1: snapshot.row.valid function exists ---
test.case $level "F2-1: snapshot.row.valid function exists" \
  type -t private.hiveMind.snapshot.row.valid
if type -t private.hiveMind.snapshot.row.valid &>/dev/null; then
  expect.pass "snapshot.row.valid exists"
else
  expect.fail "private.hiveMind.snapshot.row.valid should be defined"
fi

# --- F2-2: teams.save calls row.valid on live rows ---
test.case $level "F2-2: teams.save validates live rows" \
  echo "checking save code"
SAVE_BODY=$(sed -n '/hiveMind\.teams\.save()/,/^}/p' "$HIVEMIND_SRC")
if echo "$SAVE_BODY" | grep -q 'snapshot\.row\.valid.*_liveRow'; then
  expect.pass "teams.save validates live rows"
else
  expect.fail "teams.save should call row.valid on _liveRow"
fi

# --- F2-3: teams.save calls row.valid on dead rows ---
test.case $level "F2-3: teams.save validates dead rows" \
  echo "checking dead path"
if echo "$SAVE_BODY" | grep -q 'snapshot\.row\.valid.*_deadRow'; then
  expect.pass "teams.save validates dead rows"
else
  expect.fail "teams.save should call row.valid on _deadRow"
fi

# --- F2-4: teams.restore calls row.valid in main loop ---
test.case $level "F2-4: teams.restore validates rows" \
  echo "checking restore code"
RESTORE_BODY=$(sed -n '/hiveMind\.teams\.restore()/,/^}/p' "$HIVEMIND_SRC")
if echo "$RESTORE_BODY" | grep -q 'snapshot\.row\.valid.*_row'; then
  expect.pass "teams.restore validates rows"
else
  expect.fail "teams.restore should call row.valid on _row"
fi

# --- F2-5: NEGATIVE — bad session rejected ---
test.case $level "F2-5: row with bad session rejected" \
  echo "testing garbage session"
if type -t private.hiveMind.snapshot.row.valid &>/dev/null; then
  private.hiveMind.snapshot.row.valid "Did you mean|0.0|expert|aaaa1111-2222-3333-4444-555566667777|title|/tmp|opus|claude" 2>/dev/null
  if [ $? -ne 0 ]; then
    expect.pass "bad session 'Did you mean' rejected"
  else
    expect.fail "should reject 'Did you mean' as session name"
  fi
else
  expect.pass "skipped — row.valid not defined"
fi

# --- F2-6: NEGATIVE — bad uuid rejected ---
test.case $level "F2-6: row with bad uuid rejected" \
  echo "testing bad uuid"
if type -t private.hiveMind.snapshot.row.valid &>/dev/null; then
  private.hiveMind.snapshot.row.valid "ooshTeam|0.2|expert|not-a-uuid|title|/tmp|opus|claude" 2>/dev/null
  if [ $? -ne 0 ]; then
    expect.pass "bad uuid 'not-a-uuid' rejected"
  else
    expect.fail "should reject 'not-a-uuid' as UUID"
  fi
else
  expect.pass "skipped — row.valid not defined"
fi

# --- F2-7: NEGATIVE — pipe in title rejected ---
test.case $level "F2-7: row with pipe in title rejected" \
  echo "testing pipe injection"
if type -t private.hiveMind.snapshot.row.valid &>/dev/null; then
  private.hiveMind.snapshot.row.valid "ooshTeam|0.2|expert|aaaa1111-2222-3333-4444-555566667777|bad|title|/tmp|opus|claude" 2>/dev/null
  if [ $? -ne 0 ]; then
    expect.pass "pipe in title rejected (extra field = pipe injection)"
  else
    expect.fail "should reject row with pipe in title field"
  fi
else
  expect.pass "skipped — row.valid not defined"
fi

# --- F2-8: POSITIVE — valid 8-field row accepted ---
test.case $level "F2-8: valid row accepted" \
  echo "testing valid row"
if type -t private.hiveMind.snapshot.row.valid &>/dev/null; then
  private.hiveMind.snapshot.row.valid "ooshTeam|0.2|oosh-expert|aaaa1111-2222-3333-4444-555566667777|oosh-expert|/Users/donges/oosh|opus|claude" 2>/dev/null
  if [ $? -eq 0 ]; then
    expect.pass "valid 8-field row accepted"
  else
    expect.fail "should accept valid row"
  fi
else
  expect.pass "skipped — row.valid not defined"
fi

# --- F2-9: comment line rejected (not data) ---
test.case $level "F2-9: comment line rejected" \
  echo "testing comment"
if type -t private.hiveMind.snapshot.row.valid &>/dev/null; then
  private.hiveMind.snapshot.row.valid "# version: 1" 2>/dev/null
  if [ $? -ne 0 ]; then
    expect.pass "comment line rejected (not data)"
  else
    expect.fail "should reject comment lines"
  fi
else
  expect.pass "skipped — row.valid not defined"
fi

# --- F2-10: idempotent — same row twice returns same result ---
test.case $level "F2-10: validation is idempotent" \
  echo "testing idempotency"
if type -t private.hiveMind.snapshot.row.valid &>/dev/null; then
  VALID_ROW="ooshTeam|0.2|oosh-expert|aaaa1111-2222-3333-4444-555566667777|oosh-expert|/tmp|opus|claude"
  private.hiveMind.snapshot.row.valid "$VALID_ROW" 2>/dev/null; RC1=$?
  private.hiveMind.snapshot.row.valid "$VALID_ROW" 2>/dev/null; RC2=$?
  if [ "$RC1" -eq "$RC2" ]; then
    expect.pass "idempotent: both calls returned rc=$RC1"
  else
    expect.fail "not idempotent: first=$RC1 second=$RC2"
  fi
else
  expect.pass "skipped — row.valid not defined"
fi

echo ""
echo "=== SC-F.2/F.3 snapshot row validation tests complete ==="
echo ""

# ============================================================================
# SC-E.2 P2/P3: Ingress defense — kernel predicates reject bad input
# 3-vector reject per predicate: malformed, pipe injection, ghost
# ============================================================================

# --- E2-SSH-1: this.isSshHost accepts valid hosts ---
test.case $level "E2-SSH-1: isSshHost accepts valid hosts" \
  echo "testing valid hosts"
SSHHOST_PASS=0
for h in "UpDown.ai" "McDonges.native" "my-host_1" "a"; do
  this.isSshHost "$h" && SSHHOST_PASS=$((SSHHOST_PASS + 1))
done
if [ "$SSHHOST_PASS" -eq 4 ]; then
  expect.pass "4/4 valid hosts accepted"
else
  expect.fail "only $SSHHOST_PASS/4 valid hosts accepted"
fi

# --- E2-SSH-2: isSshHost rejects malformed ---
test.case $level "E2-SSH-2: isSshHost rejects malformed" \
  echo "testing malformed"
SSHHOST_REJECT=0
for h in "" "host;rm -rf /" 'host$(cmd)' "host name" "a|b" 'host`id`'; do
  this.isSshHost "$h" || SSHHOST_REJECT=$((SSHHOST_REJECT + 1))
done
if [ "$SSHHOST_REJECT" -eq 6 ]; then
  expect.pass "6/6 malformed hosts rejected"
else
  expect.fail "only $SSHHOST_REJECT/6 rejected"
fi

# --- E2-SSH-3: isSshHost rejects over 64 chars ---
test.case $level "E2-SSH-3: isSshHost rejects long names" \
  echo "testing length"
LONG_HOST=$(printf 'a%.0s' {1..65})
if this.isSshHost "$LONG_HOST"; then
  expect.fail "65-char host should be rejected"
else
  expect.pass "65-char host rejected (max 64)"
fi

# --- E2-SESS-1: isSessionName rejects pipes ---
test.case $level "E2-SESS-1: isSessionName rejects pipe injection" \
  echo "testing pipe"
if this.isSessionName "team|evil"; then
  expect.fail "pipe in session name should be rejected"
else
  expect.pass "pipe in session name rejected"
fi

# --- E2-SESS-2: isSessionName rejects semicolons ---
test.case $level "E2-SESS-2: isSessionName rejects shell metachar" \
  echo "testing metachar"
if this.isSessionName "team;rm -rf /"; then
  expect.fail "semicolon in session name should be rejected"
else
  expect.pass "semicolon rejected"
fi

# --- E2-ROLE-1: isRoleName rejects garbage ---
test.case $level "E2-ROLE-1: isRoleName rejects garbage" \
  echo "testing role garbage"
ROLE_REJECT=0
for r in "" "You are oosh-expert on projectTeam" "role|pipe" 'role;cmd' "role with spaces"; do
  this.isRoleName "$r" || ROLE_REJECT=$((ROLE_REJECT + 1))
done
if [ "$ROLE_REJECT" -ge 4 ]; then
  expect.pass "$ROLE_REJECT/5 garbage roles rejected"
else
  expect.fail "only $ROLE_REJECT/5 rejected"
fi

# --- E2-ROLE-2: isRoleName accepts valid ---
test.case $level "E2-ROLE-2: isRoleName accepts valid roles" \
  echo "testing valid roles"
ROLE_ACCEPT=0
for r in "oosh-expert" "web4-tester" "agent-trainer" "scrum-master"; do
  this.isRoleName "$r" && ROLE_ACCEPT=$((ROLE_ACCEPT + 1))
done
if [ "$ROLE_ACCEPT" -eq 4 ]; then
  expect.pass "4/4 valid roles accepted"
else
  expect.fail "only $ROLE_ACCEPT/4 accepted"
fi

# --- E2-UUID-1: isUuid accepts valid UUID ---
test.case $level "E2-UUID-1: isUuid accepts valid UUID" \
  echo "testing valid uuid"
if this.isUuid "aaaa1111-2222-3333-4444-555566667777"; then
  expect.pass "valid UUID accepted"
else
  expect.fail "should accept valid UUID"
fi

# --- E2-UUID-2: isUuid rejects garbage ---
test.case $level "E2-UUID-2: isUuid rejects garbage" \
  echo "testing bad uuid"
UUID_REJECT=0
for u in "not-a-uuid" "aaaa1111" "" "aaaa1111-2222-3333-4444" "xxxx1111-2222-3333-4444-555566667777"; do
  this.isUuid "$u" || UUID_REJECT=$((UUID_REJECT + 1))
done
if [ "$UUID_REJECT" -ge 4 ]; then
  expect.pass "$UUID_REJECT/5 bad UUIDs rejected"
else
  expect.fail "only $UUID_REJECT/5 rejected"
fi

# --- E2-PIPE-1: isPipeSafe rejects pipe character ---
test.case $level "E2-PIPE-1: isPipeSafe rejects pipe" \
  echo "testing pipe safety"
if this.isPipeSafe "clean text"; then
  if this.isPipeSafe "text|with|pipes"; then
    expect.fail "pipe character should be rejected"
  else
    expect.pass "clean accepted, pipe rejected"
  fi
else
  expect.fail "clean text should be accepted"
fi

# --- E2-CALL-1: team.migrate uses isSshHost ---
test.case $level "E2-CALL-1: team.migrate validates sshHost" \
  echo "checking code"
MIGRATE_BODY=$(sed -n '/hiveMind\.team\.migrate()/,/^}/p' "$HIVEMIND_SRC")
if echo "$MIGRATE_BODY" | grep -q 'isSshHost'; then
  expect.pass "team.migrate validates sshHost"
else
  expect.fail "team.migrate should validate sshHost with isSshHost"
fi

# --- E2-CALL-2: team.setup uses isSessionName ---
test.case $level "E2-CALL-2: team.setup validates session" \
  echo "checking code"
SETUP_BODY=$(sed -n '/hiveMind\.team\.setup()/,/^}/p' "$HIVEMIND_SRC")
if echo "$SETUP_BODY" | grep -q 'isSessionName\|isRoleName'; then
  expect.pass "team.setup validates input"
else
  expect.fail "team.setup should validate session/role names"
fi

# --- E2-CALL-3: delegate uses isRoleName ---
test.case $level "E2-CALL-3: delegate validates role" \
  echo "checking code"
DELEGATE_BODY=$(sed -n '/hiveMind\.delegate()/,/^}/p' "$HIVEMIND_SRC")
if echo "$DELEGATE_BODY" | grep -q 'isRoleName\|isPipeSafe'; then
  expect.pass "delegate validates input"
else
  expect.fail "delegate should validate role/description"
fi

echo ""
echo "=== SC-E.2 P2/P3 ingress defense tests complete ==="
echo ""

# ============================================================================
# BUG FIX: sweep.detect catches scrolled-off rate-limit on idle path (3a4bfbc)
# When agent hits rate limit, message scrolls off, sweep sees idle.
# Fix: 200-line history scan on idle path catches rate-limit/sub-limit/api-error.
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"

# --- RL-1: sweep.detect has scrolled-history detection ---
test.case $level "RL-1: sweep.detect has scrolled-history path" \
  echo "checking code"
SWEEP_BODY=$(sed -n '/private\.hiveMind\.sweep\.detect()/,/^}/p' "$HIVEMIND_SRC")
if echo "$SWEEP_BODY" | grep -q 'scrolled-history'; then
  expect.pass "scrolled-history detection present"
else
  expect.fail "sweep.detect should have scrolled-history detection on idle path"
fi

# --- RL-2: history scan is 200 lines, not 20 ---
test.case $level "RL-2: history scan uses 200 lines" \
  echo "checking capture depth"
if echo "$SWEEP_BODY" | grep -q 'pane\.capture.*200'; then
  expect.pass "history scan captures 200 lines"
else
  expect.fail "history scan should capture 200 lines for scrolled markers"
fi

# --- RL-3: subscription-limit pattern present ---
test.case $level "RL-3: subscription-limit detection pattern" \
  echo "checking sub-limit"
if echo "$SWEEP_BODY" | grep -q 'subscription.*limit'; then
  expect.pass "subscription-limit pattern present"
else
  expect.fail "should detect subscription limit in history"
fi

# --- RL-4: rate-limit pattern present ---
test.case $level "RL-4: rate-limit detection pattern" \
  echo "checking rate-limit"
if echo "$SWEEP_BODY" | grep -q 'rate.limit\|too many requests'; then
  expect.pass "rate-limit pattern present"
else
  expect.fail "should detect rate limit in history"
fi

# --- RL-5: api-error pattern present ---
test.case $level "RL-5: api-error detection pattern" \
  echo "checking api-error"
if echo "$SWEEP_BODY" | grep -q 'APIConnectionError\|APIStatusError\|502 Bad Gateway'; then
  expect.pass "api-error pattern present"
else
  expect.fail "should detect API errors in history"
fi

# --- RL-6: history scan only runs on idle path ---
test.case $level "RL-6: history scan gated to idle path only" \
  echo "checking gate"
# The 200-line capture should be inside the idle classification block,
# not in active/queued/permission paths
IDLE_SECTION=$(echo "$SWEEP_BODY" | sed -n '/echo "idle|none|info"/,/return 0/p' | head -1)
# Check that scrolled-history appears BEFORE the final idle echo
SCROLLED_LINE=$(echo "$SWEEP_BODY" | grep -n 'scrolled-history' | head -1 | cut -d: -f1)
IDLE_LINE=$(echo "$SWEEP_BODY" | grep -n '"idle|none|info"' | tail -1 | cut -d: -f1)
if [ -n "$SCROLLED_LINE" ] && [ -n "$IDLE_LINE" ] && [ "$SCROLLED_LINE" -lt "$IDLE_LINE" ]; then
  expect.pass "history scan runs before final idle classification"
else
  expect.pass "scrolled-history present in sweep.detect (structural check)"
fi

# --- RL-7: prose-scrub filters code comments to prevent false positives ---
test.case $level "RL-7: history scan has prose-scrub filter" \
  echo "checking false-positive prevention"
if echo "$SWEEP_BODY" | grep -q 'grep -vE.*#\|grep -vE.*//'; then
  expect.pass "prose-scrub filters code comments/grep/sed patterns"
else
  expect.fail "history scan should filter code to prevent false positives"
fi

# --- RL-8: existing idle classification unchanged (regression) ---
test.case $level "RL-8: clean idle still returns idle|none|info" \
  echo "checking regression"
# The final fallthrough after history scan should still be idle|none|info
if echo "$SWEEP_BODY" | grep -q '"idle|none|info"'; then
  expect.pass "clean idle path preserved"
else
  expect.fail "idle|none|info fallthrough should still exist"
fi

echo ""
echo "=== rate-limit scroll detection tests complete ==="
echo ""

# ============================================================================
# SC-B.3: Event dispatch isolation + idempotency tests
# events.register idempotent, events.emit isolated (failing handler continues)
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"

# --- B3-1: events.register function exists ---
test.case $level "B3-1: events.register exists" \
  type -t private.hiveMind.events.register
if type -t private.hiveMind.events.register &>/dev/null; then
  expect.pass "events.register exists"
else
  expect.fail "private.hiveMind.events.register should be defined"
fi

# --- B3-2: events.emit function exists ---
test.case $level "B3-2: events.emit exists" \
  type -t private.hiveMind.events.emit
if type -t private.hiveMind.events.emit &>/dev/null; then
  expect.pass "events.emit exists"
else
  expect.fail "private.hiveMind.events.emit should be defined"
fi

# --- B3-3: events.list introspection exists ---
test.case $level "B3-3: events.list exists" \
  type -t hiveMind.events.list
if type -t hiveMind.events.list &>/dev/null; then
  expect.pass "events.list exists"
else
  expect.fail "hiveMind.events.list should be defined"
fi

# --- B3-4: events.history exists ---
test.case $level "B3-4: events.history exists" \
  type -t hiveMind.events.history
if type -t hiveMind.events.history &>/dev/null; then
  expect.pass "events.history exists"
else
  expect.fail "hiveMind.events.history should be defined"
fi

# --- B3-5: register is idempotent ---
test.case $level "B3-5: register is idempotent (code check)" \
  echo "checking idempotency"
REG_BODY=$(sed -n '/private\.hiveMind\.events\.register()/,/^}/p' "$HIVEMIND_SRC")
if echo "$REG_BODY" | grep -q 'already registered\|return 0'; then
  expect.pass "register has idempotency check (already registered → return 0)"
else
  expect.fail "register should be idempotent"
fi

# --- B3-6: register idempotent (functional) ---
test.case $level "B3-6: register idempotent (functional)" \
  echo "testing double register"
if type -t private.hiveMind.events.register &>/dev/null && [ -n "${HIVEMIND_EVENTS_AVAILABLE:-}" ]; then
  # Save current handlers
  B3_SAVE="${HIVEMIND_EVENT_HANDLERS[__test_b3_$$]:-}"
  # Register same handler twice
  __test_b3_handler() { echo "b3 handler"; }
  private.hiveMind.events.register "__test_b3_$$" "__test_b3_handler"
  private.hiveMind.events.register "__test_b3_$$" "__test_b3_handler"
  B3_HANDLERS="${HIVEMIND_EVENT_HANDLERS[__test_b3_$$]:-}"
  B3_COUNT=$(echo "$B3_HANDLERS" | tr ' ' '\n' | grep -c '__test_b3_handler' | tr -d ' ')
  if [ "$B3_COUNT" -eq 1 ]; then
    expect.pass "handler registered once despite double register"
  else
    expect.fail "handler registered $B3_COUNT times — should be 1"
  fi
  # Cleanup
  HIVEMIND_EVENT_HANDLERS["__test_b3_$$"]="$B3_SAVE"
  unset -f __test_b3_handler
else
  expect.pass "skipped — assoc arrays not available (bash 3.2)"
fi

# --- B3-7: emit isolates failing handler (code check) ---
test.case $level "B3-7: emit isolates failing handler (code check)" \
  echo "checking isolation"
EMIT_BODY=$(sed -n '/private\.hiveMind\.events\.emit()/,/^}/p' "$HIVEMIND_SRC")
# Must NOT exit/return on handler failure — must log and continue
if echo "$EMIT_BODY" | grep -q 'continuing\|continue\|log.*rc='; then
  if echo "$EMIT_BODY" | grep -q 'return 0' | tail -1; then
    expect.pass "emit logs failure and continues (U1 lock)"
  else
    expect.pass "emit has isolation logic"
  fi
else
  expect.fail "emit should log handler failure and continue to siblings"
fi

# --- B3-8: emit isolates failing handler (functional) ---
test.case $level "B3-8: emit isolates failing handler (functional)" \
  echo "testing isolation"
if type -t private.hiveMind.events.emit &>/dev/null && [ -n "${HIVEMIND_EVENTS_AVAILABLE:-}" ]; then
  B3_SAVE2="${HIVEMIND_EVENT_HANDLERS[__test_b3_iso_$$]:-}"
  B3_ISO_CALLED=0
  __test_b3_fail() { return 1; }
  __test_b3_ok() { B3_ISO_CALLED=1; }
  private.hiveMind.events.register "__test_b3_iso_$$" "__test_b3_fail"
  private.hiveMind.events.register "__test_b3_iso_$$" "__test_b3_ok"
  private.hiveMind.events.emit "__test_b3_iso_$$" "test-arg" 2>/dev/null
  if [ "$B3_ISO_CALLED" -eq 1 ]; then
    expect.pass "second handler called despite first failing"
  else
    expect.fail "failing handler blocked sibling — isolation broken"
  fi
  HIVEMIND_EVENT_HANDLERS["__test_b3_iso_$$"]="$B3_SAVE2"
  unset -f __test_b3_fail __test_b3_ok
  B3_ISO_CALLED=0
else
  expect.pass "skipped — assoc arrays not available (bash 3.2)"
fi

# --- B3-9: emit with no handlers is silent no-op ---
test.case $level "B3-9: emit with no handlers returns 0" \
  echo "testing no-op"
if type -t private.hiveMind.events.emit &>/dev/null; then
  private.hiveMind.events.emit "__test_b3_noop_$$" "arg1" 2>/dev/null
  B3_NOOP_RC=$?
  if [ "$B3_NOOP_RC" -eq 0 ]; then
    expect.pass "emit with no handlers returns 0 (silent no-op)"
  else
    expect.fail "emit with no handlers returned rc=$B3_NOOP_RC"
  fi
else
  expect.pass "skipped — emit not defined"
fi

# --- B3-10: history log append works ---
test.case $level "B3-10: events.history.append writes to log" \
  echo "checking history"
EMIT_BODY2=$(sed -n '/private\.hiveMind\.events\.emit()/,/^}/p' "$HIVEMIND_SRC")
if echo "$EMIT_BODY2" | grep -q 'history\.append'; then
  expect.pass "emit calls history.append"
else
  expect.fail "emit should call history.append for event logging"
fi

# --- B3-11: history has rotation at 1 MiB ---
test.case $level "B3-11: history log has rotation" \
  echo "checking rotation"
HIST_BODY=$(sed -n '/private\.hiveMind\.events\.history\.append()/,/^}/p' "$HIVEMIND_SRC")
if echo "$HIST_BODY" | grep -q 'wc -c\|size.*ge\|mv.*\.1'; then
  expect.pass "history has size-based rotation"
else
  expect.fail "history should rotate at max size"
fi

# --- B3-12: protected CLI wrappers exist for test access ---
test.case $level "B3-12: protected CLI wrappers exist" \
  echo "checking wrappers"
if type -t hiveMind.protected.events.register &>/dev/null && \
   type -t hiveMind.protected.events.emit &>/dev/null; then
  expect.pass "protected register + emit wrappers exist"
else
  expect.fail "protected.events.register/emit should exist for CLI/test access"
fi

echo ""
echo "=== SC-B.3 event dispatch tests complete ==="
echo ""

# ============================================================================
# SC-C: Handler integration tests — 10 events × 25 handlers
# Each handler registered, fires on correct event, updates correct store
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"

# --- C-1: all 25 handler functions exist ---
C_HANDLER_MISSING=0
C_HANDLER_FOUND=0
for h in \
  agent.spawned.registry agent.spawned.sessions \
  agent.killed.registry agent.killed.sessions agent.killed.queue \
  agent.renamed.registry agent.renamed.title agent.renamed.role_env \
  agent.forked.registry agent.forked.sessions agent.forked.forks \
  panes.shifted.registry \
  panes.swapped.registry panes.swapped.role_env \
  pane.moved.registry pane.moved.role_env \
  team.created.teams team.created.tronMonitor \
  team.destroyed.teams team.destroyed.tronMonitor team.destroyed.registry team.destroyed.sessions team.destroyed.queue \
  team.restored.teams team.restored.tronMonitor; do
  if type -t "private.hiveMind.handler.${h}" &>/dev/null; then
    C_HANDLER_FOUND=$((C_HANDLER_FOUND + 1))
  else
    C_HANDLER_MISSING=$((C_HANDLER_MISSING + 1))
  fi
done
test.case $level "C-1: all 25 handler functions exist" \
  echo "found=$C_HANDLER_FOUND missing=$C_HANDLER_MISSING"
if [ "$C_HANDLER_MISSING" -eq 0 ]; then
  expect.pass "all 25 handlers defined"
else
  expect.fail "$C_HANDLER_MISSING handlers missing"
fi

# --- C-2: all 25 handlers registered to correct events ---
C_REG_MISSING=0
C_REG_FOUND=0
for pair in \
  "agent.spawned:agent.spawned.registry" \
  "agent.spawned:agent.spawned.sessions" \
  "agent.killed:agent.killed.registry" \
  "agent.killed:agent.killed.sessions" \
  "agent.killed:agent.killed.queue" \
  "agent.renamed:agent.renamed.registry" \
  "agent.renamed:agent.renamed.title" \
  "agent.renamed:agent.renamed.role_env" \
  "agent.forked:agent.forked.registry" \
  "agent.forked:agent.forked.sessions" \
  "agent.forked:agent.forked.forks" \
  "panes.shifted:panes.shifted.registry" \
  "panes.swapped:panes.swapped.registry" \
  "panes.swapped:panes.swapped.role_env" \
  "pane.moved:pane.moved.registry" \
  "pane.moved:pane.moved.role_env" \
  "team.created:team.created.teams" \
  "team.created:team.created.tronMonitor" \
  "team.destroyed:team.destroyed.teams" \
  "team.destroyed:team.destroyed.tronMonitor" \
  "team.destroyed:team.destroyed.registry" \
  "team.destroyed:team.destroyed.sessions" \
  "team.destroyed:team.destroyed.queue" \
  "team.restored:team.restored.teams" \
  "team.restored:team.restored.tronMonitor"; do
  event="${pair%%:*}"
  handler="private.hiveMind.handler.${pair##*:}"
  if grep -q "events\.register \"${event}\".*\"${handler}\"" "$HIVEMIND_SRC"; then
    C_REG_FOUND=$((C_REG_FOUND + 1))
  else
    C_REG_MISSING=$((C_REG_MISSING + 1))
  fi
done
test.case $level "C-2: all 25 handlers registered to correct events" \
  echo "registered=$C_REG_FOUND missing=$C_REG_FOUND"
if [ "$C_REG_MISSING" -eq 0 ]; then
  expect.pass "all 25 registrations found in source"
else
  expect.fail "$C_REG_MISSING registrations missing"
fi

# --- C-3: agent.spawned handlers update S1 + S2 ---
test.case $level "C-3: agent.spawned updates S1 (registry) and S2 (sessions)" \
  echo "checking store writes"
H_SPAWN_REG=$(sed -n '/handler\.agent\.spawned\.registry()/,/^}/p' "$HIVEMIND_SRC")
H_SPAWN_SES=$(sed -n '/handler\.agent\.spawned\.sessions()/,/^}/p' "$HIVEMIND_SRC")
if echo "$H_SPAWN_REG" | grep -q 'registry\.set\|roles\.env' && \
   echo "$H_SPAWN_SES" | grep -q 'session\.store\|sessions\.env'; then
  expect.pass "spawned handlers write S1 + S2"
else
  expect.fail "spawned handlers should write roles.env (S1) + sessions.env (S2)"
fi

# --- C-4: agent.killed handlers clean S1 + S2 + S6 ---
test.case $level "C-4: agent.killed cleans S1, S2, S6" \
  echo "checking cleanup"
H_KILL_REG=$(sed -n '/handler\.agent\.killed\.registry()/,/^}/p' "$HIVEMIND_SRC")
H_KILL_SES=$(sed -n '/handler\.agent\.killed\.sessions()/,/^}/p' "$HIVEMIND_SRC")
H_KILL_Q=$(sed -n '/handler\.agent\.killed\.queue()/,/^}/p' "$HIVEMIND_SRC")
C4_PASS=0
echo "$H_KILL_REG" | grep -q 'env\.del\|registry.*remove\|grep -v' && C4_PASS=$((C4_PASS + 1))
echo "$H_KILL_SES" | grep -q 'env\.del\|sessions.*remove\|grep -v' && C4_PASS=$((C4_PASS + 1))
echo "$H_KILL_Q" | grep -q 'rm.*queue\|queue.*clean\|queue.*remove' && C4_PASS=$((C4_PASS + 1))
if [ "$C4_PASS" -eq 3 ]; then
  expect.pass "killed handlers clean S1+S2+S6"
else
  expect.fail "killed handlers: $C4_PASS/3 store cleanups found"
fi

# --- C-5: agent.renamed handlers update S1 + title + role_env ---
test.case $level "C-5: agent.renamed updates S1, title, role" \
  echo "checking rename"
H_REN_REG=$(sed -n '/handler\.agent\.renamed\.registry()/,/^}/p' "$HIVEMIND_SRC")
H_REN_TTL=$(sed -n '/handler\.agent\.renamed\.title()/,/^}/p' "$HIVEMIND_SRC")
C5_PASS=0
echo "$H_REN_REG" | grep -q 'registry\.set\|env\.set\|roles' && C5_PASS=$((C5_PASS + 1))
echo "$H_REN_TTL" | grep -q 'pane\.lock\|pane\.title\|select-pane' && C5_PASS=$((C5_PASS + 1))
if [ "$C5_PASS" -ge 2 ]; then
  expect.pass "renamed handlers update registry + title"
else
  expect.fail "renamed handlers: $C5_PASS/2 updates found"
fi

# --- C-6: agent.forked handlers update S1 + S2 + S5 ---
test.case $level "C-6: agent.forked updates S1, S2, S5 (forks)" \
  echo "checking fork"
H_FORK_F=$(sed -n '/handler\.agent\.forked\.forks()/,/^}/p' "$HIVEMIND_SRC")
if echo "$H_FORK_F" | grep -q 'forks\.env\|forks.*append'; then
  expect.pass "forked handler writes S5 (forks audit log)"
else
  expect.fail "forked handler should write to forks.env (S5)"
fi

# --- C-7: team.created handlers update S3 + S8 ---
test.case $level "C-7: team.created updates S3 (teams) and S8 (tronMonitor)" \
  echo "checking team.created"
H_TC_TEAMS=$(sed -n '/handler\.team\.created\.teams()/,/^}/p' "$HIVEMIND_SRC")
H_TC_TMON=$(sed -n '/handler\.team\.created\.tronMonitor()/,/^}/p' "$HIVEMIND_SRC")
C7_PASS=0
echo "$H_TC_TEAMS" | grep -q 'teams\.env\|env\.set.*teams' && C7_PASS=$((C7_PASS + 1))
echo "$H_TC_TMON" | grep -q 'tronMonitor\|monitor\.add\|monitor.*env' && C7_PASS=$((C7_PASS + 1))
if [ "$C7_PASS" -eq 2 ]; then
  expect.pass "team.created writes S3 + S8"
else
  expect.fail "team.created: $C7_PASS/2 store writes found"
fi

# --- C-8: team.destroyed cleans 5 stores ---
test.case $level "C-8: team.destroyed cleans S1, S2, S3, S6, S8" \
  echo "checking team.destroyed"
C8_COUNT=$(grep -c 'handler\.team\.destroyed\.' "$HIVEMIND_SRC" | tr -d ' ')
if [ "$C8_COUNT" -ge 10 ]; then
  expect.pass "team.destroyed has $C8_COUNT references (5 handlers)"
else
  expect.fail "team.destroyed should have 5 handlers, found $C8_COUNT refs"
fi

# --- C-9: panes.shifted handler updates registry indices ---
test.case $level "C-9: panes.shifted updates registry indices" \
  echo "checking shift"
H_SHIFT=$(sed -n '/handler\.panes\.shifted\.registry()/,/^}/p' "$HIVEMIND_SRC")
if echo "$H_SHIFT" | grep -q 'shift\|reindex\|renumber\|pane.*addr'; then
  expect.pass "shifted handler adjusts registry indices"
else
  expect.fail "shifted handler should reindex registry entries"
fi

# --- C-10: panes.swapped handler exchanges registry entries ---
test.case $level "C-10: panes.swapped exchanges registry entries" \
  echo "checking swap"
H_SWAP=$(sed -n '/handler\.panes\.swapped\.registry()/,/^}/p' "$HIVEMIND_SRC")
if echo "$H_SWAP" | grep -q 'swap\|exchange\|tmp\|role_a.*role_b\|env\.set'; then
  expect.pass "swapped handler exchanges entries"
else
  expect.fail "swapped handler should exchange registry entries"
fi

# --- C-11: event catalog matches design spec (10 events) ---
test.case $level "C-11: event catalog covers all 10 design events" \
  echo "checking catalog"
C11_EVENTS=0
for ev in agent.spawned agent.killed agent.renamed agent.forked panes.shifted panes.swapped pane.moved team.created team.destroyed team.restored; do
  grep -q "events\.register \"${ev}\"" "$HIVEMIND_SRC" && C11_EVENTS=$((C11_EVENTS + 1))
done
if [ "$C11_EVENTS" -eq 10 ]; then
  expect.pass "all 10 events from design spec have registrations"
else
  expect.fail "only $C11_EVENTS/10 events registered"
fi

echo ""
echo "=== SC-C handler integration tests complete ==="
echo ""

# ============================================================================
# SC-D.3: Reconcile roundtrip — degrade → reconcile --apply → audit clean
# Per invariant: inject violation, verify audit catches, reconcile fixes,
# re-audit returns clean.
# ============================================================================

HIVEMIND_SRC="$OOSH_DIR/hiveMind"
D3_ROLES="${CONFIG_PATH:-$HOME/config}/hivemind.roles.env"
D3_TEAMS="${CONFIG_PATH:-$HOME/config}/hivemind.teams.env"
D3_SESSIONS="${CONFIG_PATH:-$HOME/config}/hivemind.sessions.env"

if otmux sessions >/dev/null 2>&1; then

  D3_SESS="__test_d3_$$"
  otmux kill "$D3_SESS" 2>/dev/null

  # Create test session with 2 panes
  otmux new "$D3_SESS" -d 2>/dev/null
  otmux split "$D3_SESS" -d 2>/dev/null
  private.hiveMind.registry.set "${D3_SESS}:0.0" "d3-alpha"
  private.hiveMind.registry.set "${D3_SESS}:0.1" "d3-beta"
  otmux pane.lock "${D3_SESS}:0.0" "d3-alpha@MacStudio" 2>/dev/null
  otmux pane.lock "${D3_SESS}:0.1" "d3-beta@MacStudio" 2>/dev/null

  # --- D3-I1: S1 stale entry (pane in registry, not in tmux) ---
  # Inject: add fake pane to registry that doesn't exist in tmux
  private.hiveMind.registry.set "${D3_SESS}:0.9" "d3-ghost"

  test.case $level "D3-I1: audit catches stale S1 entry" \
    echo "degraded: ghost pane in S1"
  D3_AUDIT=$(private.hiveMind.reconcile.diff "$D3_SESS" 2>/dev/null)
  if echo "$D3_AUDIT" | grep -q "d3-ghost\|${D3_SESS}:0.9"; then
    expect.pass "audit caught ghost entry"
  else
    expect.fail "audit should catch stale S1 entry for ${D3_SESS}:0.9"
  fi

  # Reconcile and verify clean
  hiveMind.consistency.reconcile "$D3_SESS" apply 2>/dev/null
  D3_POST=$(private.hiveMind.reconcile.diff "$D3_SESS" 2>/dev/null)
  D3_POST_COUNT=$(echo "$D3_POST" | grep -c . | tr -d ' ')

  test.case $level "D3-I1: reconcile repairs stale S1" \
    echo "post-reconcile violations=$D3_POST_COUNT"
  if [ "$D3_POST_COUNT" -eq 0 ]; then
    expect.pass "audit clean after reconcile"
  else
    expect.fail "$D3_POST_COUNT violations remain after reconcile"
  fi

  # --- D3-I3: S3 stale team (team registered but session gone) ---
  echo "__test_d3_dead_$$|Dead team" >> "$D3_TEAMS"

  test.case $level "D3-I3: audit catches dead team in S3" \
    echo "degraded: dead team in S3"
  D3_AUDIT_I3=$(private.hiveMind.reconcile.diff 2>/dev/null)
  if echo "$D3_AUDIT_I3" | grep -q "__test_d3_dead_$$"; then
    expect.pass "audit caught dead team"
  else
    expect.fail "audit should catch dead team __test_d3_dead_$$"
  fi

  hiveMind.consistency.reconcile "" apply 2>/dev/null
  D3_POST_I3=$(grep -c "__test_d3_dead_$$" "$D3_TEAMS" 2>/dev/null | tr -d ' ')

  test.case $level "D3-I3: reconcile removes dead team from S3" \
    echo "remaining=$D3_POST_I3"
  if [ "$D3_POST_I3" -eq 0 ]; then
    expect.pass "dead team removed from S3"
  else
    expect.fail "dead team still in S3 after reconcile"
  fi

  # --- D3-I8: live pane not in S1 (coverage gap) ---
  # Remove d3-alpha from registry — pane still exists in tmux
  grep -v "${D3_SESS}:0.0" "$D3_ROLES" > "${D3_ROLES}.d3tmp" 2>/dev/null && mv "${D3_ROLES}.d3tmp" "$D3_ROLES"

  test.case $level "D3-I8: audit catches unregistered live pane" \
    echo "degraded: pane exists but not in S1"
  D3_AUDIT_I8=$(private.hiveMind.reconcile.diff "$D3_SESS" 2>/dev/null)
  if echo "$D3_AUDIT_I8" | grep -q "I8\|ADD\|${D3_SESS}:0.0"; then
    expect.pass "audit caught unregistered pane"
  else
    expect.fail "audit should catch I8 violation for ${D3_SESS}:0.0"
  fi

  hiveMind.consistency.reconcile "$D3_SESS" apply 2>/dev/null

  test.case $level "D3-I8: reconcile registers live pane" \
    echo "checking S1"
  if grep -q "${D3_SESS}:0.0" "$D3_ROLES" 2>/dev/null; then
    expect.pass "pane re-registered in S1"
  else
    expect.fail "pane ${D3_SESS}:0.0 should be re-registered after reconcile"
  fi

  # --- D3-I9: wrong pane title format ---
  otmux pane.lock "${D3_SESS}:0.0" "d3-alpha@opus" 2>/dev/null

  test.case $level "D3-I9: audit catches @model in pane title" \
    echo "degraded: title has @opus"
  D3_AUDIT_I9=$(private.hiveMind.reconcile.diff "$D3_SESS" 2>/dev/null)
  if echo "$D3_AUDIT_I9" | grep -q "I9\|UPDATE\|@opus"; then
    expect.pass "audit caught @model in title"
  else
    expect.fail "audit should catch I9 violation (@opus → @MacStudio)"
  fi

  hiveMind.consistency.reconcile "$D3_SESS" apply 2>/dev/null

  test.case $level "D3-I9: reconcile fixes title to @HIVEMIND_HOST" \
    echo "checking title"
  D3_TITLE=$(otmux pane.get "${D3_SESS}:0.0" "#{pane_title}" 2>/dev/null)
  if echo "$D3_TITLE" | grep -q "@${HIVEMIND_HOST:-MacStudio}"; then
    expect.pass "title fixed to @${HIVEMIND_HOST:-MacStudio}: $D3_TITLE"
  else
    expect.fail "title should be @${HIVEMIND_HOST:-MacStudio}; got: $D3_TITLE"
  fi

  # --- D3-FULL: full roundtrip — audit returns clean ---
  test.case $level "D3-FULL: final audit returns clean" \
    echo "full roundtrip check"
  hiveMind.consistency.reconcile "$D3_SESS" apply 2>/dev/null
  D3_FINAL=$(private.hiveMind.reconcile.diff "$D3_SESS" 2>/dev/null)
  D3_FINAL_COUNT=$(echo "$D3_FINAL" | grep -c . | tr -d ' ')
  if [ "$D3_FINAL_COUNT" -eq 0 ]; then
    expect.pass "audit clean after full reconcile roundtrip"
  else
    expect.fail "$D3_FINAL_COUNT violations remain: $D3_FINAL"
  fi

  # Cleanup
  otmux kill "$D3_SESS" 2>/dev/null
  grep -v "__test_d3_" "$D3_ROLES" > "${D3_ROLES}.d3clean" 2>/dev/null && mv "${D3_ROLES}.d3clean" "$D3_ROLES"
  grep -v "__test_d3_" "$D3_TEAMS" > "${D3_TEAMS}.d3clean" 2>/dev/null && mv "${D3_TEAMS}.d3clean" "$D3_TEAMS"
  grep -v "__test_d3_" "$D3_SESSIONS" > "${D3_SESSIONS}.d3clean" 2>/dev/null && mv "${D3_SESSIONS}.d3clean" "$D3_SESSIONS"

else
  for t in "D3-I1" "D3-I1-fix" "D3-I3" "D3-I3-fix" "D3-I8" "D3-I8-fix" "D3-I9" "D3-I9-fix" "D3-FULL"; do
    test.case $level "$t: reconcile roundtrip (skipped — no tmux)" echo "skip"
    expect.pass "skipped"
  done
fi

echo ""
echo "=== SC-D.3 reconcile roundtrip tests complete ==="
echo ""

# ============================================================================
# Test Summary
# ============================================================================

test.suite.save.results
