#!/usr/bin/env bash
# bash harness for logs-read.sh rc-spawn JSONL retrieval (Task 585).
#
# Covers the three in-scope deliverables:
#   1. `logs-read.sh <key>` (bare, no type) resolves the configDir Claude tree
#      and emits a merged session+subagent timeline. Key forms tested:
#      session_<bridge>, bare <bridge>, full <uuid>, <uuid> prefix.
#   2. A subagent `is_error:true` tool_result is flagged inline in the timeline
#      (agentType + failing tool + error text), and absent when the session is
#      clean.
#   3. `logs-read.sh --scan-subagent-errors` lists every subagents/agent-*.jsonl
#      carrying an is_error result, and only those.
#
# The fake configDir is pointed at via CLAUDE_CONFIG_DIR (the same override the
# session manager honours), so no real ~/.<brand> tree is touched. Each case
# builds an rc-spawn-shaped install (data/accounts/<id>/ with NO logs/ subdir)
# to prove the JSONL path does not depend on the dead per-account logs tree.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOGS_READ="$SCRIPT_DIR/logs-read.sh"
if [[ ! -x "$LOGS_READ" ]]; then
  echo "FATAL: $LOGS_READ not executable" >&2
  exit 1
fi

UUID_A="6031941e-0000-4000-8000-000000000001"
UUID_C="c0c0c0c0-0000-4000-8000-0000000000c0"
UUID_CLEAN="c1ea0000-0000-4000-8000-00000000c1ea"
BRIDGE="TESTBRIDGE01"

PASS=0
FAIL=0

# Build an rc-spawn-shaped install root + a fake CLAUDE tree. Echos two paths
# on stdout: "<logs_read_script> <claude_config_dir>".
setup_tree() {
  local root="$1"
  mkdir -p "$root/platform/scripts"
  mkdir -p "$root/data/accounts/acct-585"   # account dir exists, but NO logs/ — rc-spawn shape
  ln -sf "$LOGS_READ" "$root/platform/scripts/logs-read.sh"
  mkdir -p "$HOME/.$(basename "$root")/logs" # server.log home for best-effort missing-on-resolve
  local cfg="$root/cfg/.claude"
  mkdir -p "$cfg/sessions" "$cfg/projects/-fake-cwd"
  echo "$root/platform/scripts/logs-read.sh $cfg"
}

cleanup_tree() {
  local root="$1"
  rm -rf "$root"
  rm -rf "$HOME/.$(basename "$root")"
}

# Write a parent JSONL with a couple of turns.
write_parent() {
  local cfg="$1" uuid="$2"
  local f="$cfg/projects/-fake-cwd/${uuid}.jsonl"
  {
    printf '%s\n' '{"type":"user","timestamp":"2026-05-31T19:40:00.000Z","uuid":"p1","message":{"role":"user","content":"make me a pdf"}}'
    printf '%s\n' '{"type":"assistant","timestamp":"2026-05-31T19:40:02.000Z","uuid":"p2","message":{"role":"assistant","model":"claude-opus-5","content":[{"type":"text","text":"dispatching content-producer"}]}}'
  } > "$f"
}

# Write a FAILING subagent transcript (is_error tool_result) + its meta.
write_subagent_failed() {
  local cfg="$1" parent_uuid="$2" agent="$3" atype="$4"
  local d="$cfg/projects/-fake-cwd/${parent_uuid}/subagents"
  mkdir -p "$d"
  {
    printf '%s\n' '{"type":"user","timestamp":"2026-05-31T19:40:10.000Z","uuid":"s1","message":{"role":"user","content":"produce the pdf and deliver it"}}'
    printf '%s\n' '{"type":"assistant","timestamp":"2026-05-31T19:40:20.000Z","uuid":"s2","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_DEAD","name":"Bash","input":{"command":"SendUserFile /tmp/out.pdf"}}]}}'
    printf '%s\n' '{"type":"user","timestamp":"2026-05-31T19:40:21.000Z","uuid":"s3","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_DEAD","is_error":true,"content":"/bin/bash: line 1: SendUserFile: command not found"}]},"toolUseResult":"Error: Exit code 127"}'
  } > "$d/${agent}.jsonl"
  printf '{"agentType":"%s","description":"render pdf"}\n' "$atype" > "$d/${agent}.meta.json"
}

# Write a parent JSONL that contains its OWN failing tool_result (NOT a
# subagent error — a parent Bash that exited non-zero). Used to prove the
# parent's own errors are not mislabelled as subagent errors.
write_parent_with_error() {
  local cfg="$1" uuid="$2"
  local f="$cfg/projects/-fake-cwd/${uuid}.jsonl"
  {
    printf '%s\n' '{"type":"user","timestamp":"2026-05-31T19:39:00.000Z","uuid":"e1","message":{"role":"user","content":"check the repo"}}'
    printf '%s\n' '{"type":"assistant","timestamp":"2026-05-31T19:39:02.000Z","uuid":"e2","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_PARENT","name":"Bash","input":{"command":"grep nonesuch ."}}]}}'
    printf '%s\n' '{"type":"user","timestamp":"2026-05-31T19:39:03.000Z","uuid":"e3","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_PARENT","is_error":true,"content":"Exit code 1 PARENT_OWN_GREP_MISS"}]},"toolUseResult":"Error: Exit code 1"}'
  } > "$f"
}

# Write a parent JSONL carrying BOTH harness rejections and the classes that
# must NOT be treated as rejections. A rejection is a call the CLI refused to
# dispatch, so the tool never ran; everything else here either ran and failed or
# is a different fault. Both InputValidationError sub-classes are covered:
# unparseable JSON (carries __unparsedToolInput) and schema-valid JSON that
# failed validation (no such marker, and the majority class in practice).
write_parent_with_rejections() {
  local cfg="$1" uuid="$2"
  local f="$cfg/projects/-fake-cwd/${uuid}.jsonl"
  {
    printf '%s\n' '{"type":"user","timestamp":"2026-07-16T15:59:00.000Z","uuid":"r0","message":{"role":"user","content":"send it"}}'
    # 2 x rejection sub-class A (unparseable JSON) on ONE tool -> census x2
    printf '%s\n' '{"type":"assistant","timestamp":"2026-07-16T15:59:01.000Z","uuid":"r1","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_R1","name":"outlook-mail-send","input":{"__unparsedToolInput":"{\"to\": bare@x.co}"}}]}}'
    printf '%s\n' '{"type":"user","timestamp":"2026-07-16T15:59:02.000Z","uuid":"r2","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_R1","is_error":true,"content":"<tool_use_error>InputValidationError: outlook-mail-send was called with input that could not be parsed as JSON.\nYou sent (first 200 of 670 bytes): {\"to\": bare@x.co} REJECT_A_ONE</tool_use_error>"}]}}'
    printf '%s\n' '{"type":"assistant","timestamp":"2026-07-16T15:59:03.000Z","uuid":"r3","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_R2","name":"outlook-mail-send","input":{"__unparsedToolInput":"{\"to\": bare@x.co}"}}]}}'
    printf '%s\n' '{"type":"user","timestamp":"2026-07-16T15:59:04.000Z","uuid":"r4","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_R2","is_error":true,"content":"<tool_use_error>InputValidationError: outlook-mail-send was called with input that could not be parsed as JSON.\nYou sent (first 200 of 670 bytes): {\"to\": bare@x.co} REJECT_A_TWO</tool_use_error>"}]}}'
    # rejection sub-class B: JSON parsed fine, schema validation failed
    printf '%s\n' '{"type":"assistant","timestamp":"2026-07-16T15:59:05.000Z","uuid":"r5","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_R3","name":"Read","input":{"offset":"x"}}]}}'
    printf '%s\n' '{"type":"user","timestamp":"2026-07-16T15:59:06.000Z","uuid":"r6","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_R3","is_error":true,"content":"<tool_use_error>InputValidationError: Read failed due to the following issue: The parameter `offset` type is expected as `number` REJECT_B_ONE</tool_use_error>"}]}}'
    # NOT a rejection: unknown tool (different fault, has its own PostToolUse hook)
    printf '%s\n' '{"type":"assistant","timestamp":"2026-07-16T15:59:07.000Z","uuid":"r7","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_N1","name":"work-create","input":{}}]}}'
    printf '%s\n' '{"type":"user","timestamp":"2026-07-16T15:59:08.000Z","uuid":"r8","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_N1","is_error":true,"content":"<tool_use_error>Error: No such tool available: work-create NOTREJ_NOTOOL</tool_use_error>"}]}}'
    # NOT a rejection: MCP server-side validation (the call DID reach the server)
    printf '%s\n' '{"type":"assistant","timestamp":"2026-07-16T15:59:09.000Z","uuid":"r9","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_N2","name":"outlook-mail-fetch-body","input":{}}]}}'
    printf '%s\n' '{"type":"user","timestamp":"2026-07-16T15:59:10.000Z","uuid":"rA","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_N2","is_error":true,"content":"MCP error -32602: Input validation error: id: Required NOTREJ_32602"}]}}'
    # NOT a rejection: built-in tool that RAN and failed its precondition
    printf '%s\n' '{"type":"assistant","timestamp":"2026-07-16T15:59:11.000Z","uuid":"rB","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_N3","name":"Edit","input":{}}]}}'
    printf '%s\n' '{"type":"user","timestamp":"2026-07-16T15:59:12.000Z","uuid":"rC","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_N3","is_error":true,"content":"<tool_use_error>File has not been read yet. Read it first before writing to it. NOTREJ_UNREAD</tool_use_error>"}]}}'
  } > "$f"
}

# Write a subagent transcript whose ONLY error is a harness rejection. Used to
# prove --scan-subagent-errors does not report a rejection-only subagent as an
# error-carrying one: the subagent did not fail, a call was never dispatched.
write_subagent_rejection_only() {
  local cfg="$1" parent_uuid="$2" agent="$3" atype="$4"
  local d="$cfg/projects/-fake-cwd/${parent_uuid}/subagents"
  mkdir -p "$d"
  {
    printf '%s\n' '{"type":"user","timestamp":"2026-07-16T16:00:00.000Z","uuid":"j1","message":{"role":"user","content":"read it"}}'
    printf '%s\n' '{"type":"assistant","timestamp":"2026-07-16T16:00:01.000Z","uuid":"j2","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_SR","name":"Read","input":{"__unparsedToolInput":"{\"file_path\": /x}"}}]}}'
    printf '%s\n' '{"type":"user","timestamp":"2026-07-16T16:00:02.000Z","uuid":"j3","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_SR","is_error":true,"content":"<tool_use_error>InputValidationError: Read was called with input that could not be parsed as JSON.\nYou sent (first 200 of 30 bytes): {\"file_path\": /x} SUBREJ_ONLY</tool_use_error>"}]}}'
  } > "$d/${agent}.jsonl"
  printf '{"agentType":"%s","description":"read a file"}\n' "$atype" > "$d/${agent}.meta.json"
}

# Write a CLEAN subagent transcript (no errors) + its meta.
write_subagent_clean() {
  local cfg="$1" parent_uuid="$2" agent="$3" atype="$4"
  local d="$cfg/projects/-fake-cwd/${parent_uuid}/subagents"
  mkdir -p "$d"
  {
    printf '%s\n' '{"type":"user","timestamp":"2026-05-31T19:41:10.000Z","uuid":"q1","message":{"role":"user","content":"review the diff"}}'
    printf '%s\n' '{"type":"assistant","timestamp":"2026-05-31T19:41:12.000Z","uuid":"q2","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_OK","name":"Read","input":{"file_path":"/x"}}]}}'
    printf '%s\n' '{"type":"user","timestamp":"2026-05-31T19:41:13.000Z","uuid":"q3","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_OK","content":"ok"}]}}'
  } > "$d/${agent}.jsonl"
  printf '{"agentType":"%s","description":"review"}\n' "$atype" > "$d/${agent}.meta.json"
}

write_pidfile() {
  local cfg="$1" pid="$2" uuid="$3" bridge="$4"
  printf '{"pid":%s,"sessionId":"%s","bridgeSessionId":"session_%s","cwd":"/fake/cwd","startedAt":1780000000000}\n' \
    "$pid" "$uuid" "$bridge" > "$cfg/sessions/${pid}.json"
}

# meta sidecar carrying bridgeIds (persistent bridge->uuid map, survives PID-file deletion).
write_meta_bridgeids() {
  local cfg="$1" uuid="$2" bridge="$3"
  printf '{"senderId":"s1","role":"admin","channel":"browser","url":null,"startedAt":"2026-05-31T19:40:00.000Z","permissionMode":null,"effectivePermissionMode":null,"model":null,"hidden":false,"specialist":null,"scopeUnitToken":null,"bridgeIds":["%s"]}\n' \
    "$bridge" > "$cfg/projects/-fake-cwd/${uuid}.meta.json"
}

# Parent transcript whose BODY embeds a bridge key string (no pidfile, no
# bridgeIds) — exercises the content-grep last-resort resolver tier.
write_parent_with_key_in_body() {
  local cfg="$1" uuid="$2" keystr="$3"
  printf '%s\n' "{\"type\":\"user\",\"timestamp\":\"2026-05-31T19:38:00.000Z\",\"uuid\":\"b1\",\"message\":{\"role\":\"user\",\"content\":\"resumed from ${keystr} earlier\"}}" \
    > "$cfg/projects/-fake-cwd/${uuid}.jsonl"
}

run_case() {
  local name="$1"; shift
  echo ""
  echo "=== CASE: $name ==="
  if "$@"; then
    PASS=$((PASS + 1)); echo "PASS: $name"
  else
    FAIL=$((FAIL + 1)); echo "FAIL: $name"
  fi
}

# Capture stdout, stderr, rc of a logs-read.sh invocation under a fake config dir.
# Sets globals: OUT ERR RC.
invoke() {
  local script="$1" cfg="$2"; shift 2
  local errf; errf=$(mktemp)
  RC=0
  OUT=$(CLAUDE_CONFIG_DIR="$cfg" "$script" "$@" 2>"$errf") || RC=$?
  ERR=$(cat "$errf"); rm -f "$errf"
}

# --- Case A: bare key via PID-file bridge → timeline + flagged subagent error ---
case_bridge_timeline_flagged() {
  local root="/tmp/maxy-585-A-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent "$cfg" "$UUID_A"
  write_subagent_failed "$cfg" "$UUID_A" "agent-aDEAD0000" "content-producer"
  write_pidfile "$cfg" 4242 "$UUID_A" "$BRIDGE"

  invoke "$script" "$cfg" "session_${BRIDGE}"
  cleanup_tree "$root"

  [[ $RC -eq 0 ]]                        || { echo "  expected exit 0, got $RC; err=$ERR"; return 1; }
  [[ "$OUT" == *"content-producer"* ]]   || { echo "  missing agentType content-producer"; return 1; }
  [[ "$OUT" == *"SendUserFile"* ]]       || { echo "  missing failing command SendUserFile"; return 1; }
  [[ "$OUT" == *"command not found"* ]]  || { echo "  missing error text"; return 1; }
  [[ "$OUT" == *"SUBAGENT ERROR"* ]]     || { echo "  missing SUBAGENT ERROR flag"; return 1; }
  [[ "$OUT" == *"6031941e"* ]]           || { echo "  missing resolved session uuid"; return 1; }
  return 0
}

# --- Case B: clean session → timeline, NO error flag ---
case_clean_no_flag() {
  local root="/tmp/maxy-585-B-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent "$cfg" "$UUID_A"
  write_subagent_clean "$cfg" "$UUID_A" "agent-aCLEAN000" "code-reviewer"
  write_pidfile "$cfg" 4243 "$UUID_A" "$BRIDGE"

  invoke "$script" "$cfg" "session_${BRIDGE}"
  cleanup_tree "$root"

  [[ $RC -eq 0 ]]                       || { echo "  expected exit 0, got $RC; err=$ERR"; return 1; }
  [[ "$OUT" == *"code-reviewer"* ]]     || { echo "  missing clean subagent in timeline"; return 1; }
  [[ "$OUT" != *"SUBAGENT ERROR"* ]]    || { echo "  unexpected SUBAGENT ERROR flag on clean session"; return 1; }
  return 0
}

# --- Case C: resolve via bridgeIds sidecar when PID file is absent ---
case_resolve_via_bridgeids() {
  local root="/tmp/maxy-585-C-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent "$cfg" "$UUID_C"
  write_subagent_failed "$cfg" "$UUID_C" "agent-aBEEF0000" "content-producer"
  write_meta_bridgeids "$cfg" "$UUID_C" "ENDEDBRIDGE9"   # no pidfile — session ended

  invoke "$script" "$cfg" "session_ENDEDBRIDGE9"
  cleanup_tree "$root"

  [[ $RC -eq 0 ]]              || { echo "  expected exit 0, got $RC; err=$ERR"; return 1; }
  [[ "$OUT" == *"c0c0c0c0"* ]] || { echo "  did not resolve UUID_C via bridgeIds"; return 1; }
  return 0
}

# --- Case D: resolve via UUID directly (full) ---
case_resolve_uuid_direct() {
  local root="/tmp/maxy-585-D-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent "$cfg" "$UUID_A"
  write_subagent_clean "$cfg" "$UUID_A" "agent-aOK000000" "code-reviewer"

  invoke "$script" "$cfg" "$UUID_A"
  cleanup_tree "$root"

  [[ $RC -eq 0 ]]             || { echo "  expected exit 0, got $RC; err=$ERR"; return 1; }
  [[ "$OUT" == *"6031941e"* ]] || { echo "  did not return timeline for UUID_A"; return 1; }
  return 0
}

# --- Case E: --scan-subagent-errors lists failed subagent only ---
case_scan_lists_failed_only() {
  local root="/tmp/maxy-585-E-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent "$cfg" "$UUID_A"
  write_subagent_failed "$cfg" "$UUID_A" "agent-aDEAD0000" "content-producer"
  write_parent "$cfg" "$UUID_CLEAN"
  write_subagent_clean "$cfg" "$UUID_CLEAN" "agent-aSAFE0000" "code-reviewer"

  invoke "$script" "$cfg" "--scan-subagent-errors"
  cleanup_tree "$root"

  [[ $RC -eq 0 ]]                          || { echo "  expected exit 0, got $RC; err=$ERR"; return 1; }
  [[ "$OUT" == *"agent-aDEAD0000"* ]]      || { echo "  failed subagent not listed"; return 1; }
  [[ "$OUT" == *"content-producer"* ]]     || { echo "  failed subagent agentType missing"; return 1; }
  [[ "$OUT" == *"command not found"* ]]    || { echo "  error text missing in scan"; return 1; }
  [[ "$OUT" != *"agent-aSAFE0000"* ]]      || { echo "  clean subagent wrongly listed"; return 1; }
  return 0
}

# --- Case G: parent's OWN tool error is not mislabelled as a subagent error ---
case_parent_error_not_subagent() {
  local root="/tmp/maxy-585-G-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent_with_error "$cfg" "$UUID_A"
  write_subagent_clean "$cfg" "$UUID_A" "agent-aCLEAN111" "code-reviewer"
  write_pidfile "$cfg" 4244 "$UUID_A" "$BRIDGE"

  invoke "$script" "$cfg" "session_${BRIDGE}"
  cleanup_tree "$root"

  [[ $RC -eq 0 ]]                          || { echo "  expected exit 0, got $RC; err=$ERR"; return 1; }
  [[ "$OUT" == *"PARENT_OWN_GREP_MISS"* ]] || { echo "  parent tool error not shown in timeline"; return 1; }
  [[ "$OUT" != *"SUBAGENT ERROR"* ]]       || { echo "  parent error wrongly tagged SUBAGENT ERROR"; return 1; }
  [[ "$OUT" == *"subagent-errors: 0"* ]]   || { echo "  header miscounts parent error as subagent error"; return 1; }
  return 0
}

# --- Case J: harness rejection is distinguished from a tool that RAN and failed ---
# The 1692 defect: a call the CLI refused to dispatch rendered identically to a
# tool that ran and returned a failure, so a rejection loop read as "the tool is
# broken" while the tool was healthy. Only InputValidationError may be relabelled.
case_rejection_classified_and_counted() {
  local root="/tmp/maxy-1692-J-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent_with_rejections "$cfg" "$UUID_A"
  write_pidfile "$cfg" 4255 "$UUID_A" "$BRIDGE"

  invoke "$script" "$cfg" "session_${BRIDGE}"
  cleanup_tree "$root"

  [[ $RC -eq 0 ]] || { echo "  expected exit 0, got $RC; err=$ERR"; return 1; }

  # Both InputValidationError sub-classes are rejections (neither dispatched).
  [[ "$OUT" == *"REJECTED"*"REJECT_A_ONE"* ]] || { echo "  sub-class A (unparseable) not flagged REJECTED"; return 1; }
  [[ "$OUT" == *"REJECTED"*"REJECT_B_ONE"* ]] || { echo "  sub-class B (schema-invalid) not flagged REJECTED"; return 1; }

  # The exclusions MUST keep the plain tool-error rendering. Widening the
  # predicate to the bare <tool_use_error> wrapper is the regression this pins.
  local l
  for l in NOTREJ_NOTOOL NOTREJ_32602 NOTREJ_UNREAD; do
    grep -q "tool error.*$l" <<<"$OUT" || { echo "  $l lost its '‼ tool error' rendering"; return 1; }
    grep -q "REJECTED.*$l"   <<<"$OUT" && { echo "  $l wrongly flagged REJECTED"; return 1; }
  done

  # Repetition is the diagnostic fact: 2 identical calls on one tool, counted.
  [[ "$OUT" == *"rejections: 3"* ]]            || { echo "  census missing or miscounted (want 3)"; return 1; }
  [[ "$OUT" == *"outlook-mail-send x2"* ]]     || { echo "  census does not count the repeat per tool"; return 1; }
  return 0
}

# --- Case K: a clean session emits NO census line (non-regression) ---
case_no_rejections_no_census() {
  local root="/tmp/maxy-1692-K-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent_with_error "$cfg" "$UUID_A"
  write_pidfile "$cfg" 4256 "$UUID_A" "$BRIDGE"

  invoke "$script" "$cfg" "session_${BRIDGE}"
  cleanup_tree "$root"

  [[ $RC -eq 0 ]]                    || { echo "  expected exit 0, got $RC"; return 1; }
  [[ "$OUT" != *"rejections:"* ]]    || { echo "  census line emitted for a session with no rejections"; return 1; }
  [[ "$OUT" != *"REJECTED"* ]]       || { echo "  genuine tool error wrongly flagged REJECTED"; return 1; }
  return 0
}

# --- Case L: --scan-subagent-errors does not report a rejection-only subagent ---
# A rejection is not a subagent failure: the subagent did not fail, a call was
# never dispatched. Counting it re-creates the 1692 conflation one mode over.
case_scan_ignores_rejection_only_subagent() {
  local root="/tmp/maxy-1692-L-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent "$cfg" "$UUID_A"
  write_subagent_rejection_only "$cfg" "$UUID_A" "agent-aREJ00001" "content-producer"
  write_subagent_failed "$cfg" "$UUID_A" "agent-aFAIL0001" "pdf-renderer"

  invoke "$script" "$cfg" --scan-subagent-errors
  cleanup_tree "$root"

  [[ $RC -eq 0 ]]                    || { echo "  expected exit 0, got $RC; err=$ERR"; return 1; }
  [[ "$OUT" == *"aFAIL0001"* ]]      || { echo "  genuinely failed subagent missing from scan"; return 1; }
  [[ "$OUT" != *"SUBREJ_ONLY"* ]]    || { echo "  rejection-only subagent reported as error-carrying"; return 1; }
  [[ "$OUT" != *"aREJ00001"* ]]      || { echo "  rejection-only subagent listed by scan"; return 1; }
  return 0
}

# --- Case I: content-grep resolves a unique body match (last-resort tier) ---
case_content_grep_single() {
  local root="/tmp/maxy-585-I-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent_with_key_in_body "$cfg" "$UUID_A" "session_SOLOKEYxyz1"  # no pidfile, no bridgeIds

  invoke "$script" "$cfg" "session_SOLOKEYxyz1"
  cleanup_tree "$root"

  [[ $RC -eq 0 ]]              || { echo "  expected exit 0 (single content match), got $RC; err=$ERR"; return 1; }
  [[ "$OUT" == *"6031941e"* ]] || { echo "  content-grep did not resolve the unique match"; return 1; }
  return 0
}

# --- Case H: content-grep refuses when the key matches multiple transcripts ---
case_content_grep_ambiguous_refuses() {
  local root="/tmp/maxy-585-H-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent_with_key_in_body "$cfg" "$UUID_A" "session_AMBIGKEYxyz"
  write_parent_with_key_in_body "$cfg" "$UUID_C" "session_AMBIGKEYxyz"  # same key in two bodies

  invoke "$script" "$cfg" "session_AMBIGKEYxyz"
  cleanup_tree "$root"

  # Must NOT silently pick one of the two — refuse (exit 1), like uuid-prefix ambiguity.
  [[ $RC -eq 1 ]] || { echo "  expected exit 1 (ambiguous content match), got $RC; out=$OUT"; return 1; }
  return 0
}

# --- Case F: unresolvable key → exit 1 (clean miss, not a crash) ---
case_unresolvable_miss() {
  local root="/tmp/maxy-585-F-$$"; local out
  out=$(setup_tree "$root"); local script="${out% *}"; local cfg="${out#* }"
  write_parent "$cfg" "$UUID_A"

  invoke "$script" "$cfg" "session_NOSUCHBRIDGE"
  cleanup_tree "$root"

  [[ $RC -eq 1 ]] || { echo "  expected exit 1 on unresolvable key, got $RC"; return 1; }
  return 0
}

run_case "bare key via PID bridge → timeline + flagged subagent error" case_bridge_timeline_flagged
run_case "clean session → timeline, no error flag"                     case_clean_no_flag
run_case "resolve via bridgeIds sidecar (PID file absent)"             case_resolve_via_bridgeids
run_case "resolve via full UUID directly"                              case_resolve_uuid_direct
run_case "--scan-subagent-errors lists failed subagent only"           case_scan_lists_failed_only
run_case "parent's own tool error not mislabelled SUBAGENT ERROR"      case_parent_error_not_subagent
run_case "content-grep resolves a unique body match"                   case_content_grep_single
run_case "content-grep refuses an ambiguous (multi) body match"        case_content_grep_ambiguous_refuses
run_case "unresolvable key → exit 1"                                   case_unresolvable_miss
run_case "harness rejection classified + counted, exclusions intact"   case_rejection_classified_and_counted
run_case "no rejections → no census line"                              case_no_rejections_no_census
run_case "scan ignores a rejection-only subagent"                      case_scan_ignores_rejection_only_subagent

echo ""
echo "================================================"
echo " Passed: $PASS / Failed: $FAIL"
echo "================================================"
[[ $FAIL -eq 0 ]]
