#!/usr/bin/env bash
# scripts/manual/run_server_to_rc_mode_matrix.sh
# Manual: validate server-generated UVC/UAC output against the RC target across
# the UVC modes the UI advertises. This is still a hardware-in-the-loop probe:
# it captures the real Tethys UVC/UAC endpoints and summarizes sync,
# freshness, and smoothness for each mode.
# Not part of CI: it needs the Theia/Tethys lab hosts and live USB gadget state.
#
# Reconfigure mode is intentionally a fast runtime path: it updates the remote
# Lesavka env files and cycles the UVC gadget, but it does not rebuild or
# reinstall the server binary for each mode.

set -euo pipefail

SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." >/dev/null 2>&1 && pwd)"

if (( EUID == 0 )); then
  printf 'Do not run this matrix with local sudo.\n' >&2
  printf 'Run it as your normal workstation user; the script will request sudo on the remote server host only when reconfiguring UVC.\n' >&2
  exit 64
fi

TETHYS_HOST=${TETHYS_HOST:-tethys}
LESAVKA_SERVER_HOST=${LESAVKA_SERVER_HOST:-theia}
LESAVKA_SERVER_CONNECT_HOST=${LESAVKA_SERVER_CONNECT_HOST:-38.28.125.112}
LESAVKA_SERVER_ADDR=${LESAVKA_SERVER_ADDR:-auto}
LESAVKA_SERVER_SCHEME=${LESAVKA_SERVER_SCHEME:-https}
LESAVKA_TLS_DOMAIN=${LESAVKA_TLS_DOMAIN:-lesavka-server}
LESAVKA_SERVER_REPO=${LESAVKA_SERVER_REPO:-auto}
SSH_OPTS=${SSH_OPTS:-"-o BatchMode=yes -o ConnectTimeout=30"}

LESAVKA_SERVER_RC_CORE_WEBCAM_MODES=${LESAVKA_SERVER_RC_CORE_WEBCAM_MODES:-1280x720@20,1280x720@30,1920x1080@20,1920x1080@30}
LESAVKA_SERVER_RC_MODES=${LESAVKA_SERVER_RC_MODES:-${LESAVKA_SERVER_RC_CORE_WEBCAM_MODES}}
LESAVKA_SERVER_RC_PROFILE=${LESAVKA_SERVER_RC_PROFILE:-mjpeg}
LESAVKA_SERVER_RC_AUDIO_PROFILE=${LESAVKA_SERVER_RC_AUDIO_PROFILE:-pcm}
LESAVKA_SERVER_RC_NORMALIZED_PROFILE=mjpeg
LESAVKA_SERVER_RC_NORMALIZED_AUDIO_PROFILE=pcm
LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US=${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US:-${LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US:-0}}
LESAVKA_SERVER_RC_DEFAULT_VIDEO_DELAY_US=${LESAVKA_SERVER_RC_DEFAULT_VIDEO_DELAY_US:-135090}
LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US=${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US:-1280x720@20=${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US},1280x720@30=${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US},1920x1080@20=${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US},1920x1080@30=${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US}}
LESAVKA_SERVER_RC_MJPEG_MODE_DELAYS_US=${LESAVKA_SERVER_RC_MJPEG_MODE_DELAYS_US:-1280x720@20=162659,1280x720@30=135090,1920x1080@20=160045,1920x1080@30=127952}
LESAVKA_SERVER_RC_HEVC_MODE_DELAYS_US=${LESAVKA_SERVER_RC_HEVC_MODE_DELAYS_US:-1280x720@20=173852,1280x720@30=110000,1920x1080@20=160045,1920x1080@30=127952}
case "${LESAVKA_SERVER_RC_PROFILE,,}" in
  hevc|h265|h.265)
    LESAVKA_SERVER_RC_NORMALIZED_PROFILE=hevc
    LESAVKA_SERVER_RC_MODE_DELAYS_US=${LESAVKA_SERVER_RC_MODE_DELAYS_US:-${LESAVKA_SERVER_RC_HEVC_MODE_DELAYS_US}}
    CAPTURE_SECONDS=${CAPTURE_SECONDS:-90}
    PROBE_TIMEOUT_SECONDS=${PROBE_TIMEOUT_SECONDS:-90}
    export CAPTURE_SECONDS PROBE_TIMEOUT_SECONDS
    ;;
  *)
    LESAVKA_SERVER_RC_NORMALIZED_PROFILE=mjpeg
    LESAVKA_SERVER_RC_MODE_DELAYS_US=${LESAVKA_SERVER_RC_MODE_DELAYS_US:-${LESAVKA_SERVER_RC_MJPEG_MODE_DELAYS_US}}
    ;;
esac
case "${LESAVKA_SERVER_RC_AUDIO_PROFILE,,}" in
  opus|compressed|voice)
    LESAVKA_SERVER_RC_NORMALIZED_AUDIO_PROFILE=opus
    ;;
  *)
    LESAVKA_SERVER_RC_NORMALIZED_AUDIO_PROFILE=pcm
    ;;
esac
LESAVKA_SERVER_RC_CALIBRATION_PROFILE="${LESAVKA_SERVER_RC_NORMALIZED_PROFILE}+${LESAVKA_SERVER_RC_NORMALIZED_AUDIO_PROFILE}"
LESAVKA_SERVER_RC_MODE_DISCOVERY_SIZES=${LESAVKA_SERVER_RC_MODE_DISCOVERY_SIZES:-1280x720,1920x1080}
LESAVKA_SERVER_RC_MODE_DISCOVERY_FPS=${LESAVKA_SERVER_RC_MODE_DISCOVERY_FPS:-20,30}
LESAVKA_SERVER_RC_MODE_DISCOVERY_INCLUDE_REGEX=${LESAVKA_SERVER_RC_MODE_DISCOVERY_INCLUDE_REGEX:-Logitech|BRIO|C9[0-9]+|HD UVC WebCam|USB2[.]0 HD|Integrated Camera|Webcam|Camera}
LESAVKA_SERVER_RC_MODE_DISCOVERY_EXCLUDE_REGEX=${LESAVKA_SERVER_RC_MODE_DISCOVERY_EXCLUDE_REGEX:-Lesavka|UGREEN|MACROSILICON|Composite|Capture}
LESAVKA_SERVER_RC_MODE_SOURCE=${LESAVKA_SERVER_RC_MODE_SOURCE:-configured}
LESAVKA_SERVER_RC_RECONFIGURE=${LESAVKA_SERVER_RC_RECONFIGURE:-0}
LESAVKA_SERVER_RC_RECONFIGURE_REF=${LESAVKA_SERVER_RC_RECONFIGURE_REF:-master}
LESAVKA_SERVER_RC_RECONFIGURE_UPDATE=${LESAVKA_SERVER_RC_RECONFIGURE_UPDATE:-0}
LESAVKA_SERVER_RC_RECONFIGURE_COMMAND=${LESAVKA_SERVER_RC_RECONFIGURE_COMMAND:-}
LESAVKA_SERVER_RC_RECONFIGURE_STRATEGY=${LESAVKA_SERVER_RC_RECONFIGURE_STRATEGY:-runtime}
LESAVKA_SERVER_RC_RECONFIGURE_CODEC=${LESAVKA_SERVER_RC_RECONFIGURE_CODEC:-mjpeg}
LESAVKA_SERVER_RC_ALLOW_GADGET_RESET=${LESAVKA_SERVER_RC_ALLOW_GADGET_RESET:-1}
LESAVKA_SERVER_RC_FORCE_GADGET_REBUILD=${LESAVKA_SERVER_RC_FORCE_GADGET_REBUILD:-1}
LESAVKA_SERVER_RC_RECONFIGURE_SETTLE_SECONDS=${LESAVKA_SERVER_RC_RECONFIGURE_SETTLE_SECONDS:-4}
LESAVKA_SERVER_RC_RECONFIGURE_VERBOSE=${LESAVKA_SERVER_RC_RECONFIGURE_VERBOSE:-0}
LESAVKA_SERVER_RC_PROMPT_SUDO_EARLY=${LESAVKA_SERVER_RC_PROMPT_SUDO_EARLY:-1}
LESAVKA_SERVER_RC_REMOTE_SUDO_PASSWORD=${LESAVKA_SERVER_RC_REMOTE_SUDO_PASSWORD:-}
LESAVKA_SERVER_RC_START_DELAY_SECONDS=${LESAVKA_SERVER_RC_START_DELAY_SECONDS:-0}
LESAVKA_SERVER_RC_WAIT_TETHYS_READY=${LESAVKA_SERVER_RC_WAIT_TETHYS_READY:-1}
LESAVKA_SERVER_RC_TETHYS_READY_TIMEOUT_SECONDS=${LESAVKA_SERVER_RC_TETHYS_READY_TIMEOUT_SECONDS:-60}
LESAVKA_SERVER_RC_TETHYS_SETTLE_SECONDS=${LESAVKA_SERVER_RC_TETHYS_SETTLE_SECONDS:-6}
LESAVKA_SERVER_RC_PREROLL_DISCARD_SECONDS=${LESAVKA_SERVER_RC_PREROLL_DISCARD_SECONDS:-3}
LESAVKA_SERVER_RC_PROBE_PREBUILD=${LESAVKA_SERVER_RC_PROBE_PREBUILD:-1}
LESAVKA_SERVER_RC_CONTINUE_ON_FAIL=${LESAVKA_SERVER_RC_CONTINUE_ON_FAIL:-1}
LESAVKA_SERVER_RC_TUNE_DELAYS=${LESAVKA_SERVER_RC_TUNE_DELAYS:-1}
LESAVKA_SERVER_RC_TUNE_CONFIRM=${LESAVKA_SERVER_RC_TUNE_CONFIRM:-1}
LESAVKA_SERVER_RC_TUNE_MIN_PAIRS=${LESAVKA_SERVER_RC_TUNE_MIN_PAIRS:-13}
LESAVKA_SERVER_RC_TUNE_MAX_ABS_SKEW_MS=${LESAVKA_SERVER_RC_TUNE_MAX_ABS_SKEW_MS:-1000}
LESAVKA_SERVER_RC_TUNE_MAX_DRIFT_MS=${LESAVKA_SERVER_RC_TUNE_MAX_DRIFT_MS:-80}
LESAVKA_SERVER_RC_TUNE_MAX_STEP_US=${LESAVKA_SERVER_RC_TUNE_MAX_STEP_US:-500000}
LESAVKA_SERVER_RC_TUNE_MIN_CHANGE_US=${LESAVKA_SERVER_RC_TUNE_MIN_CHANGE_US:-5000}
LESAVKA_SERVER_RC_REPEAT_COUNT=${LESAVKA_SERVER_RC_REPEAT_COUNT:-1}
LESAVKA_SERVER_RC_VERBOSE_PROBES=${LESAVKA_SERVER_RC_VERBOSE_PROBES:-1}
LESAVKA_SERVER_RC_STATIC_MIN_RUNS=${LESAVKA_SERVER_RC_STATIC_MIN_RUNS:-3}
LESAVKA_SERVER_RC_STATIC_MAX_SPREAD_US=${LESAVKA_SERVER_RC_STATIC_MAX_SPREAD_US:-30000}
LESAVKA_SERVER_RC_STATIC_MAX_P95_SKEW_MS=${LESAVKA_SERVER_RC_STATIC_MAX_P95_SKEW_MS:-35}
LESAVKA_SERVER_RC_STATIC_MAX_MEDIAN_SKEW_MS=${LESAVKA_SERVER_RC_STATIC_MAX_MEDIAN_SKEW_MS:-20}
LESAVKA_SERVER_RC_STATIC_REQUIRE_FRESHNESS=${LESAVKA_SERVER_RC_STATIC_REQUIRE_FRESHNESS:-1}
LESAVKA_SERVER_RC_STATIC_REQUIRE_SMOOTHNESS=${LESAVKA_SERVER_RC_STATIC_REQUIRE_SMOOTHNESS:-0}

LESAVKA_SERVER_RC_FRESHNESS_MAX_AGE_MS=${LESAVKA_SERVER_RC_FRESHNESS_MAX_AGE_MS:-350}
LESAVKA_SERVER_RC_FRESHNESS_MAX_DRIFT_MS=${LESAVKA_SERVER_RC_FRESHNESS_MAX_DRIFT_MS:-100}
LESAVKA_SERVER_RC_FRESHNESS_MAX_CLOCK_UNCERTAINTY_MS=${LESAVKA_SERVER_RC_FRESHNESS_MAX_CLOCK_UNCERTAINTY_MS:-250}
LESAVKA_SERVER_RC_FRESHNESS_MIN_PAIRS=${LESAVKA_SERVER_RC_FRESHNESS_MIN_PAIRS:-${LESAVKA_SERVER_RC_TUNE_MIN_PAIRS}}
LESAVKA_SERVER_RC_REQUIRE_FRESHNESS_PASS=${LESAVKA_SERVER_RC_REQUIRE_FRESHNESS_PASS:-1}
LESAVKA_SERVER_RC_REQUIRE_SYNC_PASS=${LESAVKA_SERVER_RC_REQUIRE_SYNC_PASS:-1}
LESAVKA_SERVER_RC_MIN_CODED_PAIRS=${LESAVKA_SERVER_RC_MIN_CODED_PAIRS:-${LESAVKA_SERVER_RC_FRESHNESS_MIN_PAIRS}}
LESAVKA_SERVER_RC_REQUIRE_ALL_CODED_PAIRS=${LESAVKA_SERVER_RC_REQUIRE_ALL_CODED_PAIRS:-0}
LESAVKA_SERVER_RC_REQUIRE_SMOOTHNESS_PASS=${LESAVKA_SERVER_RC_REQUIRE_SMOOTHNESS_PASS:-0}
LESAVKA_SERVER_RC_SIGNAL_READY=${LESAVKA_SERVER_RC_SIGNAL_READY:-1}
LESAVKA_SERVER_RC_SIGNAL_READY_MODE=${LESAVKA_SERVER_RC_SIGNAL_READY_MODE:-conditioned_capture}
LESAVKA_SERVER_RC_SIGNAL_READY_MIN_PAIRS=${LESAVKA_SERVER_RC_SIGNAL_READY_MIN_PAIRS:-3}
LESAVKA_SERVER_RC_SIGNAL_READY_DURATION_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_READY_DURATION_SECONDS:-12}
LESAVKA_SERVER_RC_SIGNAL_READY_WARMUP_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_READY_WARMUP_SECONDS:-1}
LESAVKA_SERVER_RC_SIGNAL_READY_ATTEMPTS=${LESAVKA_SERVER_RC_SIGNAL_READY_ATTEMPTS:-4}
LESAVKA_SERVER_RC_SIGNAL_READY_RETRY_DELAY_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_READY_RETRY_DELAY_SECONDS:-5}
LESAVKA_SERVER_RC_SIGNAL_CONDITION_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_SECONDS:-12}
LESAVKA_SERVER_RC_SIGNAL_CONDITION_WARMUP_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_WARMUP_SECONDS:-1}
LESAVKA_SERVER_RC_SIGNAL_CONDITION_GAP_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_GAP_SECONDS:-1}
LESAVKA_SERVER_RC_SIGNAL_CONDITION_EVENT_WIDTH_CODES=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_EVENT_WIDTH_CODES:-${PROBE_EVENT_WIDTH_CODES:-1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}}
LESAVKA_SERVER_RC_ANALYSIS_TIMELINE_WINDOW=${LESAVKA_SERVER_RC_ANALYSIS_TIMELINE_WINDOW:-auto}

LESAVKA_SERVER_RC_MAX_VIDEO_HICCUPS=${LESAVKA_SERVER_RC_MAX_VIDEO_HICCUPS:-0}
LESAVKA_SERVER_RC_MAX_AUDIO_HICCUPS=${LESAVKA_SERVER_RC_MAX_AUDIO_HICCUPS:-0}
LESAVKA_SERVER_RC_MAX_VIDEO_P95_JITTER_MS=${LESAVKA_SERVER_RC_MAX_VIDEO_P95_JITTER_MS:-1}
LESAVKA_SERVER_RC_MAX_AUDIO_P95_JITTER_MS=${LESAVKA_SERVER_RC_MAX_AUDIO_P95_JITTER_MS:-1}
LESAVKA_SERVER_RC_MAX_VIDEO_MISSING_FRAMES=${LESAVKA_SERVER_RC_MAX_VIDEO_MISSING_FRAMES:-12}
LESAVKA_SERVER_RC_MAX_VIDEO_UNDECODABLE_FRAMES=${LESAVKA_SERVER_RC_MAX_VIDEO_UNDECODABLE_FRAMES:-12}
LESAVKA_SERVER_RC_MAX_VIDEO_DUPLICATE_FRAMES=${LESAVKA_SERVER_RC_MAX_VIDEO_DUPLICATE_FRAMES:-5}
LESAVKA_SERVER_RC_MAX_AUDIO_LOW_RMS_WINDOWS=${LESAVKA_SERVER_RC_MAX_AUDIO_LOW_RMS_WINDOWS:-2}

PROBE_DURATION_SECONDS=${PROBE_DURATION_SECONDS:-20}
PROBE_WARMUP_SECONDS=${PROBE_WARMUP_SECONDS:-4}
PROBE_EVENT_WIDTH_CODES=${PROBE_EVENT_WIDTH_CODES:-1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}
REMOTE_PULSE_CAPTURE_TOOL=${REMOTE_PULSE_CAPTURE_TOOL:-gst}
REMOTE_PULSE_VIDEO_MODE=${REMOTE_PULSE_VIDEO_MODE:-cfr}
REMOTE_CAPTURE_STACK=${REMOTE_CAPTURE_STACK:-pulse}
REMOTE_AUDIO_SOURCE=${REMOTE_AUDIO_SOURCE:-auto}
REMOTE_CAPTURE_ALLOW_ALSA_FALLBACK=${REMOTE_CAPTURE_ALLOW_ALSA_FALLBACK:-0}
REMOTE_CAPTURE_READY_SETTLE_SECONDS=${REMOTE_CAPTURE_READY_SETTLE_SECONDS:-1}
LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US=${LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US:-0}

STAMP="$(date +%Y%m%d-%H%M%S)"
LOCAL_OUTPUT_DIR=${LOCAL_OUTPUT_DIR:-/tmp}
MATRIX_REPORT_DIR=${MATRIX_REPORT_DIR:-"${LOCAL_OUTPUT_DIR%/}/lesavka-server-rc-mode-matrix-${STAMP}"}
MATRIX_SUMMARY_JSON="${MATRIX_REPORT_DIR}/mode-matrix-summary.json"
MATRIX_SUMMARY_CSV="${MATRIX_REPORT_DIR}/mode-matrix-summary.csv"
MATRIX_SUMMARY_TXT="${MATRIX_REPORT_DIR}/mode-matrix-summary.txt"
MATRIX_DELAY_JSON="${MATRIX_REPORT_DIR}/mode-delay-recommendations.json"
MATRIX_DELAY_ENV="${MATRIX_REPORT_DIR}/mode-delay-recommendations.env"
MATRIX_STATIC_JSON="${MATRIX_REPORT_DIR}/mode-static-calibration.json"
MATRIX_STATIC_CSV="${MATRIX_REPORT_DIR}/mode-static-calibration.csv"
MATRIX_STATIC_TXT="${MATRIX_REPORT_DIR}/mode-static-calibration.txt"
MATRIX_STATIC_ENV="${MATRIX_REPORT_DIR}/mode-static-calibration.env"
MATRIX_RUN_LOG="${MATRIX_REPORT_DIR}/mode-matrix-run.log"
mkdir -p "${MATRIX_REPORT_DIR}"
exec > >(tee -a "${MATRIX_RUN_LOG}") 2>&1

mode_id() {
  local mode=$1
  printf '%s\n' "${mode//@/_}" | tr -c '[:alnum:]_.-' '_'
}

parse_mode() {
  local mode=$1
  if [[ ! "${mode}" =~ ^([0-9]+)x([0-9]+)@([0-9]+)$ ]]; then
    printf 'invalid mode %s; expected WIDTHxHEIGHT@FPS\n' "${mode}" >&2
    exit 64
  fi
  printf '%s %s %s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
}

lookup_mode_delay_us() {
  local mode=$1
  local delay_map=$2
  local default_value=$3
  local entry key value
  IFS=',' read -r -a delay_entries <<<"${delay_map}"
  for entry in "${delay_entries[@]}"; do
    key=${entry%%=*}
    value=${entry#*=}
    if [[ "${key}" == "${mode}" && "${value}" =~ ^-?[0-9]+$ ]]; then
      printf '%s\n' "${value}"
      return 0
    fi
  done
  printf '%s\n' "${default_value}"
}

lookup_audio_delay_us() {
  lookup_mode_delay_us "$1" "${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US}" "${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US}"
}

lookup_video_delay_us() {
  lookup_mode_delay_us "$1" "${LESAVKA_SERVER_RC_MODE_DELAYS_US}" "${LESAVKA_SERVER_RC_DEFAULT_VIDEO_DELAY_US}"
}

artifact_dir_from_log() {
  local log_path=$1
  local search_dir=$2
  local artifact_dir
  artifact_dir="$(awk -F': ' '/^artifact_dir: / {print $2}' "${log_path}" 2>/dev/null | tail -n1 || true)"
  if [[ -z "${artifact_dir}" ]]; then
    artifact_dir="$(find "${search_dir}" -mindepth 1 -maxdepth 1 -type d -name 'lesavka-output-delay-probe-*' | sort | tail -n1 || true)"
  fi
  printf '%s\n' "${artifact_dir}"
}

RUN_MODE_PROBE_STATUS=0
run_mode_probe() {
  local width=$1
  local height=$2
  local fps=$3
  local audio_delay_us=$4
  local video_delay_us=$5
  local output_dir=$6
  local log_path=$7
  local probe_duration_seconds=${8:-${PROBE_DURATION_SECONDS}}
  local probe_warmup_seconds=${9:-${PROBE_WARMUP_SECONDS}}
  local min_pairs=${10:-${LESAVKA_SERVER_RC_FRESHNESS_MIN_PAIRS}}
  local conditioning_seconds=${11:-${LESAVKA_SERVER_RC_SIGNAL_CONDITION_SECONDS}}
  local analysis_timeline_window=${LESAVKA_SERVER_RC_ANALYSIS_TIMELINE_WINDOW}
  if [[ "${LESAVKA_SERVER_RC_SIGNAL_READY}" == "0" ]]; then
    conditioning_seconds=0
  fi
  if [[ "${analysis_timeline_window}" == "auto" ]]; then
    if [[ "${conditioning_seconds}" =~ ^[0-9]+$ && "${conditioning_seconds}" -gt 0 ]]; then
      analysis_timeline_window=1
    else
      analysis_timeline_window=0
    fi
  fi

  local -a probe_env=(
    "TETHYS_HOST=${TETHYS_HOST}"
    "LESAVKA_SERVER_HOST=${LESAVKA_SERVER_HOST}"
    "LESAVKA_SERVER_CONNECT_HOST=${LESAVKA_SERVER_CONNECT_HOST}"
    "LESAVKA_SERVER_ADDR=${LESAVKA_SERVER_ADDR}"
    "LESAVKA_SERVER_SCHEME=${LESAVKA_SERVER_SCHEME}"
    "LESAVKA_TLS_DOMAIN=${LESAVKA_TLS_DOMAIN}"
    "SSH_OPTS=${SSH_OPTS}"
    "REMOTE_PULSE_CAPTURE_TOOL=${REMOTE_PULSE_CAPTURE_TOOL}"
    "REMOTE_PULSE_VIDEO_MODE=${REMOTE_PULSE_VIDEO_MODE}"
    "REMOTE_CAPTURE_STACK=${REMOTE_CAPTURE_STACK}"
    "REMOTE_AUDIO_SOURCE=${REMOTE_AUDIO_SOURCE}"
    "REMOTE_CAPTURE_ALLOW_ALSA_FALLBACK=${REMOTE_CAPTURE_ALLOW_ALSA_FALLBACK}"
    "REMOTE_CAPTURE_PREROLL_DISCARD_SECONDS=${LESAVKA_SERVER_RC_PREROLL_DISCARD_SECONDS}"
    "REMOTE_CAPTURE_READY_SETTLE_SECONDS=${REMOTE_CAPTURE_READY_SETTLE_SECONDS}"
    "PROBE_PREBUILD=0"
    "VIDEO_SIZE=${width}x${height}"
    "VIDEO_FPS=${fps}"
    "VIDEO_FORMAT=mjpeg"
    "REMOTE_EXPECT_UVC_WIDTH=${width}"
    "REMOTE_EXPECT_UVC_HEIGHT=${height}"
    "REMOTE_EXPECT_UVC_FPS=${fps}"
    "LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US=${audio_delay_us}"
    "LESAVKA_OUTPUT_DELAY_PROBE_VIDEO_DELAY_US=${video_delay_us}"
    "LESAVKA_OUTPUT_DELAY_APPLY=0"
    "LESAVKA_OUTPUT_DELAY_SAVE=0"
    "LESAVKA_OUTPUT_REQUIRE_SYNC_PASS=0"
    "LESAVKA_OUTPUT_DELAY_MIN_PAIRS=${min_pairs}"
    "LESAVKA_OUTPUT_DELAY_MAX_ABS_SKEW_MS=${LESAVKA_SERVER_RC_TUNE_MAX_ABS_SKEW_MS}"
    "LESAVKA_OUTPUT_DELAY_MAX_DRIFT_MS=${LESAVKA_SERVER_RC_TUNE_MAX_DRIFT_MS}"
    "LESAVKA_OUTPUT_DELAY_MAX_STEP_US=${LESAVKA_SERVER_RC_TUNE_MAX_STEP_US}"
    "LESAVKA_OUTPUT_FRESHNESS_MAX_AGE_MS=${LESAVKA_SERVER_RC_FRESHNESS_MAX_AGE_MS}"
    "LESAVKA_OUTPUT_FRESHNESS_MAX_DRIFT_MS=${LESAVKA_SERVER_RC_FRESHNESS_MAX_DRIFT_MS}"
    "LESAVKA_OUTPUT_FRESHNESS_MAX_CLOCK_UNCERTAINTY_MS=${LESAVKA_SERVER_RC_FRESHNESS_MAX_CLOCK_UNCERTAINTY_MS}"
    "LESAVKA_OUTPUT_FRESHNESS_MIN_PAIRS=${min_pairs}"
    "PROBE_EVENT_WIDTH_CODES=${PROBE_EVENT_WIDTH_CODES}"
    "PROBE_CONDITIONING_SECONDS=${conditioning_seconds}"
    "PROBE_CONDITIONING_WARMUP_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_WARMUP_SECONDS}"
    "PROBE_CONDITIONING_GAP_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_GAP_SECONDS}"
    "PROBE_CONDITIONING_EVENT_WIDTH_CODES=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_EVENT_WIDTH_CODES}"
    "PROBE_DURATION_SECONDS=${probe_duration_seconds}"
    "PROBE_WARMUP_SECONDS=${probe_warmup_seconds}"
    "ANALYSIS_TIMELINE_WINDOW=${analysis_timeline_window}"
    "LOCAL_OUTPUT_DIR=${output_dir}"
  )

  set +e
  if [[ "${LESAVKA_SERVER_RC_VERBOSE_PROBES}" == "0" ]]; then
    env "${probe_env[@]}" "${SCRIPT_DIR}/run_upstream_av_sync.sh" >"${log_path}" 2>&1
    RUN_MODE_PROBE_STATUS=$?
  else
    env "${probe_env[@]}" "${SCRIPT_DIR}/run_upstream_av_sync.sh" 2>&1 | tee "${log_path}"
    RUN_MODE_PROBE_STATUS=${PIPESTATUS[0]}
  fi
  set -e
}

write_tune_candidate_env() {
  local mode_result=$1
  local output_env=$2
  python3 - <<'PY' \
    "${mode_result}" \
    "${output_env}" \
    "${LESAVKA_SERVER_RC_TUNE_MIN_PAIRS}" \
    "${LESAVKA_SERVER_RC_TUNE_MAX_ABS_SKEW_MS}" \
    "${LESAVKA_SERVER_RC_TUNE_MAX_DRIFT_MS}" \
    "${LESAVKA_SERVER_RC_TUNE_MAX_STEP_US}" \
    "${LESAVKA_SERVER_RC_TUNE_MIN_CHANGE_US}"
import json
import math
import pathlib
import shlex
import sys

(
    result_path,
    output_env_path,
    min_pairs_raw,
    max_abs_skew_raw,
    max_drift_raw,
    max_step_raw,
    min_change_raw,
) = sys.argv[1:8]


def env_line(key, value):
    return f"{key}={shlex.quote(str(value))}\n"


def as_int(value, default=0):
    try:
        return int(str(value).strip())
    except Exception:
        return default


def as_float(value, default=0.0):
    try:
        result = float(str(value).strip())
    except Exception:
        return default
    return result if math.isfinite(result) else default


result = json.loads(pathlib.Path(result_path).read_text())
calibration = result.get("output_delay_calibration") or {}
sync = result.get("sync") or {}
min_pairs = max(1, as_int(min_pairs_raw, 13))
max_abs_skew_ms = max(1.0, as_float(max_abs_skew_raw, 1000.0))
max_drift_ms = max(0.0, as_float(max_drift_raw, 80.0))
max_step_us = max(1, as_int(max_step_raw, 500_000))
min_change_us = max(0, as_int(min_change_raw, 5_000))
current_audio = as_int(result.get("audio_delay_us"), 0)
current_video = as_int(result.get("video_delay_us"), 0)
target_audio = as_int(calibration.get("audio_target_offset_us"), current_audio)
target_video = as_int(calibration.get("video_target_offset_us"), current_video)
paired = as_int(calibration.get("paired_event_count"), as_int(sync.get("paired_event_count"), 0))
drift_ms = as_float(calibration.get("drift_ms"), as_float(sync.get("drift_ms"), 0.0))
max_abs_skew_ms_observed = as_float(
    calibration.get("max_abs_skew_ms"),
    as_float(sync.get("p95_abs_skew_ms"), 0.0),
)
delta_audio = target_audio - current_audio
delta_video = target_video - current_video
raw_delta_us = as_int(
    calibration.get("raw_device_delta_us"),
    delta_video if abs(delta_video) >= abs(delta_audio) else -delta_audio,
)
reasons = []

if result.get("run_status") != 0:
    reasons.append(f"seed probe exited {result.get('run_status')}")
if paired < min_pairs:
    reasons.append(f"paired_event_count {paired} < {min_pairs}")
if max_abs_skew_ms_observed > max_abs_skew_ms:
    reasons.append(
        f"max_abs_skew_ms {max_abs_skew_ms_observed:.1f} > {max_abs_skew_ms:.1f}"
    )
if abs(drift_ms) > max_drift_ms:
    reasons.append(f"abs(drift_ms) {abs(drift_ms):.1f} > {max_drift_ms:.1f}")
if abs(raw_delta_us) > max_step_us:
    reasons.append(f"raw delay correction {raw_delta_us:+d}us exceeds {max_step_us}us")
if target_audio < 0 or target_video < 0:
    reasons.append(
        f"direct confirmation delays must be non-negative, got audio={target_audio} video={target_video}"
    )
if abs(delta_audio) < min_change_us and abs(delta_video) < min_change_us:
    reasons.append(
        f"target change audio={delta_audio:+d}us video={delta_video:+d}us is below {min_change_us}us"
    )

ready = not reasons
values = {
    "tune_ready": str(ready).lower(),
    "tune_reason": "ready" if ready else "; ".join(reasons),
    "tune_audio_delay_us": target_audio,
    "tune_video_delay_us": target_video,
    "tune_audio_delta_us": delta_audio,
    "tune_video_delta_us": delta_video,
    "tune_paired_event_count": paired,
    "tune_drift_ms": f"{drift_ms:.3f}",
    "tune_max_abs_skew_ms": f"{max_abs_skew_ms_observed:.3f}",
    "tune_raw_delta_us": raw_delta_us,
}
with pathlib.Path(output_env_path).open("w") as handle:
    for key, value in values.items():
        handle.write(env_line(key, value))
PY
}

signal_readiness_passed() {
  local artifact_dir=$1
  local min_pairs=$2
  python3 - <<'PY' "${artifact_dir}" "${min_pairs}"
import json
import pathlib
import sys

artifact_dir = pathlib.Path(sys.argv[1])
min_pairs = int(sys.argv[2])

def load_json(path):
    try:
        return json.loads(path.read_text())
    except Exception:
        return {}

report = load_json(artifact_dir / "report.json")
paired = int(report.get("paired_event_count") or 0)
video = int(report.get("video_event_count") or 0)
audio = int(report.get("audio_event_count") or 0)
verdict = report.get("verdict") or {}
passed = paired >= min_pairs and video >= min_pairs and audio >= min_pairs and verdict.get("passed") is True
if not passed:
    reason = (
        f"signal readiness needs at least {min_pairs} paired coded events with sync pass; "
        f"saw paired={paired}, video={video}, audio={audio}, sync={verdict.get('status', 'unknown')}"
    )
    print(reason)
raise SystemExit(0 if passed else 1)
PY
}

write_signal_readiness_attempt_result() {
  local attempt=$1
  local artifact_dir=$2
  local run_status=$3
  local run_log=$4
  local min_pairs=$5
  local output_json=$6
  python3 - <<'PY' \
    "${attempt}" \
    "${artifact_dir}" \
    "${run_status}" \
    "${run_log}" \
    "${min_pairs}" \
    "${output_json}"
import json
import pathlib
import re
import sys

(
    attempt_raw,
    artifact_dir_raw,
    run_status_raw,
    run_log_raw,
    min_pairs_raw,
    output_json_raw,
) = sys.argv[1:]

def as_int(value, default=0):
    try:
        return int(str(value).strip())
    except Exception:
        return default

def as_float(value, default=0.0):
    try:
        return float(str(value).strip())
    except Exception:
        return default

def load_json(path):
    try:
        return json.loads(path.read_text())
    except Exception:
        return {}

def read_text(path):
    try:
        return path.read_text(errors="replace")
    except Exception:
        return ""

attempt = as_int(attempt_raw)
run_status = as_int(run_status_raw)
min_pairs = as_int(min_pairs_raw, 1)
run_log = pathlib.Path(run_log_raw)
artifact_dir = pathlib.Path(artifact_dir_raw) if artifact_dir_raw else None
if artifact_dir is None or not artifact_dir.exists():
    match = re.findall(r"^artifact_dir:\s*(.+)$", read_text(run_log), flags=re.MULTILINE)
    if match:
        artifact_dir = pathlib.Path(match[-1].strip())
if artifact_dir is None:
    artifact_dir = pathlib.Path("__missing_signal_readiness_artifact__")

report = load_json(artifact_dir / "report.json")
timeline = load_json(artifact_dir / "server-output-timeline.json")
error_log = artifact_dir / "analysis-error.log"
error_text = read_text(error_log)
if not error_text:
    error_log = artifact_dir / "analysis-error.log.tmp"
    error_text = read_text(error_log)
if not error_text:
    error_text = read_text(run_log)

events = timeline.get("events") or []
server_event_count = len(events)
server_video_handoff_count = sum(
    1
    for event in events
    if event.get("video_feed_unix_ns") is not None
    or event.get("video_feed_monotonic_us") is not None
)
server_audio_handoff_count = sum(
    1
    for event in events
    if event.get("audio_push_unix_ns") is not None
    or event.get("audio_push_monotonic_us") is not None
)

verdict = report.get("verdict") or {}
signature_coverage = report.get("signature_coverage") or {}
video_events = as_int(report.get("video_event_count"))
audio_events = as_int(report.get("audio_event_count"))
paired_events = as_int(report.get("paired_event_count"))
coded_pairs = as_int(signature_coverage.get("paired_event_count"), paired_events)
expected_pairs = as_int(signature_coverage.get("expected_event_count"))
raw_activity_delta_ms = as_float(report.get("activity_start_delta_ms"))
analyzer_failure = ""

failure_match = re.search(
    r"coded pulse common window removed one stream entirely;[^\n]*"
    r"\(video=(?P<video>\d+)\s+audio=(?P<audio>\d+)\s+raw activity delta\s+"
    r"(?P<delta>[+-]?\d+(?:\.\d+)?)\s+ms\)",
    error_text,
)
if failure_match:
    video_events = max(video_events, as_int(failure_match.group("video")))
    audio_events = max(audio_events, as_int(failure_match.group("audio")))
    raw_activity_delta_ms = as_float(failure_match.group("delta"))
    analyzer_failure = failure_match.group(0)

pairs_match = re.search(
    r"need at least\s+(?P<needed>\d+)\s+matching coded pulse pairs;\s+"
    r"saw\s+(?P<paired>\d+);\s+raw activity delta was\s+"
    r"(?P<delta>[+-]?\d+(?:\.\d+)?)\s+ms\s+"
    r"\(video=(?P<video_time>\d+(?:\.\d+)?)s\s+audio=(?P<audio_time>\d+(?:\.\d+)?)s\)",
    error_text,
)
if pairs_match:
    paired_from_error = as_int(pairs_match.group("paired"))
    paired_events = max(paired_events, paired_from_error)
    coded_pairs = max(coded_pairs, paired_from_error)
    video_events = max(video_events, paired_from_error)
    audio_events = max(audio_events, paired_from_error)
    raw_activity_delta_ms = as_float(pairs_match.group("delta"))
    analyzer_failure = pairs_match.group(0)

sync_passed = verdict.get("passed") is True
paired_ready = paired_events >= min_pairs or coded_pairs >= min_pairs
video_ready = video_events >= min_pairs
audio_ready = audio_events >= min_pairs
passed = run_status == 0 and paired_ready and video_ready and audio_ready and sync_passed

reasons = []
if run_status != 0:
    reasons.append(f"probe command exited {run_status}")
if server_event_count == 0:
    reasons.append("server did not report generated coded events")
if server_video_handoff_count == 0:
    reasons.append("server did not report video sink handoff events")
if server_audio_handoff_count == 0:
    reasons.append("server did not report audio sink handoff events")
if video_events < min_pairs:
    reasons.append(f"Tethys video coded events {video_events} < {min_pairs}")
if audio_events < min_pairs:
    reasons.append(f"Tethys audio coded events {audio_events} < {min_pairs}")
if max(paired_events, coded_pairs) < min_pairs:
    reasons.append(f"paired coded events {max(paired_events, coded_pairs)} < {min_pairs}")
if report and not sync_passed:
    reasons.append(f"sync verdict did not pass: {verdict.get('status', 'unknown')}")
if analyzer_failure:
    reasons.append(analyzer_failure)
if not reasons and passed:
    reasons.append("ready")
elif not reasons:
    reasons.append("signal readiness failed")

result = {
    "schema": "lesavka.server-rc-signal-readiness-attempt.v1",
    "attempt": attempt,
    "passed": passed,
    "reason": "; ".join(reasons),
    "run_status": run_status,
    "run_log": str(run_log),
    "artifact_dir": str(artifact_dir) if artifact_dir.exists() else "",
    "analysis_error_log": str(error_log) if error_log.exists() else "",
    "counts": {
        "server_events": server_event_count,
        "server_video_handoffs": server_video_handoff_count,
        "server_audio_handoffs": server_audio_handoff_count,
        "video_events": video_events,
        "audio_events": audio_events,
        "paired_events": paired_events,
        "coded_pairs": coded_pairs,
        "expected_pairs": expected_pairs,
    },
    "layers": {
        "server_generated_video": server_event_count > 0,
        "server_generated_audio": server_event_count > 0,
        "server_video_handoff": server_video_handoff_count > 0,
        "server_audio_handoff": server_audio_handoff_count > 0,
        "tethys_video_detected": video_events > 0,
        "tethys_audio_detected": audio_events > 0,
        "tethys_video_ready": video_ready,
        "tethys_audio_ready": audio_ready,
        "paired_coded_ready": paired_ready,
        "analyzer_sync_passed": sync_passed,
    },
    "sync": {
        "status": verdict.get("status", "unknown"),
        "passed": sync_passed,
        "p95_abs_skew_ms": as_float(verdict.get("p95_abs_skew_ms")),
        "median_skew_ms": as_float(report.get("median_skew_ms")),
        "drift_ms": as_float(report.get("drift_ms")),
        "raw_activity_delta_ms": raw_activity_delta_ms,
    },
    "analyzer_failure": analyzer_failure,
}
pathlib.Path(output_json_raw).write_text(json.dumps(result, indent=2, sort_keys=True) + "\n")
print(result["reason"])
raise SystemExit(0 if passed else 1)
PY
}

write_signal_readiness_attempts_summary() {
  local output_json=$1
  shift || true
  python3 - <<'PY' "${output_json}" "$@"
import json
import pathlib
import sys

output = pathlib.Path(sys.argv[1])
attempts = []
for raw in sys.argv[2:]:
    path = pathlib.Path(raw)
    try:
        attempts.append(json.loads(path.read_text()))
    except Exception:
        attempts.append({
            "schema": "lesavka.server-rc-signal-readiness-attempt.v1",
            "attempt_json": str(path),
            "passed": False,
            "reason": "attempt result could not be read",
        })
passed_attempt = next((attempt for attempt in attempts if attempt.get("passed")), None)
summary = {
    "schema": "lesavka.server-rc-signal-readiness-summary.v1",
    "passed": passed_attempt is not None,
    "passed_attempt": passed_attempt.get("attempt") if passed_attempt else None,
    "attempt_count": len(attempts),
    "final_reason": (
        "ready"
        if passed_attempt
        else (attempts[-1].get("reason") if attempts else "no readiness attempts ran")
    ),
    "attempts": attempts,
}
output.write_text(json.dumps(summary, indent=2, sort_keys=True) + "\n")
PY
}

write_signal_readiness_failure() {
  local mode=$1
  local width=$2
  local height=$3
  local fps=$4
  local video_delay_us=$5
  local audio_delay_us=$6
  local readiness_status=$7
  local readiness_log=$8
  local readiness_artifact_dir=$9
  local readiness_attempts_json=${10}
  local readiness_reason=${11}
  local output_json=${12}
  python3 - <<'PY' \
    "${mode}" \
    "${width}" \
    "${height}" \
    "${fps}" \
    "${video_delay_us}" \
    "${audio_delay_us}" \
    "${readiness_status}" \
    "${readiness_log}" \
    "${readiness_artifact_dir}" \
    "${readiness_attempts_json}" \
    "${readiness_reason}" \
    "${output_json}"
import json
import pathlib
import sys

(
    mode,
    width_raw,
    height_raw,
    fps_raw,
    video_delay_raw,
    audio_delay_raw,
    readiness_status_raw,
    readiness_log,
    readiness_artifact_dir,
    readiness_attempts_json,
    readiness_reason,
    output_json,
) = sys.argv[1:]

def as_int(value, default=0):
    try:
        return int(str(value).strip())
    except Exception:
        return default

def load_json(path):
    try:
        return json.loads(pathlib.Path(path).read_text())
    except Exception:
        return {}

report = load_json(pathlib.Path(readiness_artifact_dir) / "report.json")
verdict = report.get("verdict") or {}
signature_coverage = report.get("signature_coverage") or {}
readiness_attempts = load_json(readiness_attempts_json).get("attempts") if readiness_attempts_json else None
result = {
    "schema": "lesavka.server-rc-mode-result.v1",
    "mode": mode,
    "width": as_int(width_raw),
    "height": as_int(height_raw),
    "fps": as_int(fps_raw),
    "audio_delay_us": as_int(audio_delay_raw),
    "video_delay_us": as_int(video_delay_raw),
    "run_status": as_int(readiness_status_raw),
    "run_log": readiness_log,
    "artifact_dir": readiness_artifact_dir,
    "report_json": str(pathlib.Path(readiness_artifact_dir) / "report.json"),
    "passed": False,
    "failure_reasons": [f"signal readiness did not pass: {readiness_reason}"],
    "signal_readiness": {
        "passed": False,
        "reason": readiness_reason,
        "artifact_dir": readiness_artifact_dir,
        "run_log": readiness_log,
        "attempts_json": readiness_attempts_json,
        "attempts": readiness_attempts or [],
    },
    "sync": {
        "passed": verdict.get("passed") is True,
        "status": verdict.get("status", "unknown"),
        "reason": verdict.get("reason", ""),
        "p95_abs_skew_ms": float(verdict.get("p95_abs_skew_ms") or 0.0),
        "median_skew_ms": float(report.get("median_skew_ms") or 0.0),
        "drift_ms": float(report.get("drift_ms") or 0.0),
        "activity_start_delta_ms": float(report.get("activity_start_delta_ms") or 0.0),
        "first_skew_ms": float(report.get("first_skew_ms") or 0.0),
        "video_event_count": as_int(report.get("video_event_count")),
        "audio_event_count": as_int(report.get("audio_event_count")),
        "paired_event_count": as_int(report.get("paired_event_count")),
        "signature_expected_event_count": as_int(signature_coverage.get("expected_event_count")),
        "signature_paired_event_count": as_int(signature_coverage.get("paired_event_count")),
        "signature_missing_event_ids": signature_coverage.get("missing_event_ids") or [],
        "signature_missing_codes": signature_coverage.get("missing_codes") or [],
        "signature_unknown_pair_identity_count": as_int(signature_coverage.get("unknown_pair_identity_count")),
    },
    "freshness": {
        "status": "unknown",
        "reason": "measured probe skipped because signal readiness failed",
        "worst_event_age_with_uncertainty_ms": 0.0,
    },
    "smoothness": {},
    "output_delay_calibration": {},
}
pathlib.Path(output_json).write_text(json.dumps(result, indent=2, sort_keys=True) + "\n")
PY
}

discover_local_webcam_modes() {
  if ! command -v python3 >/dev/null 2>&1; then
    printf 'LESAVKA_SERVER_RC_MODES=auto requires python3 for local webcam mode discovery.\n' >&2
    exit 64
  fi
  if ! command -v v4l2-ctl >/dev/null 2>&1; then
    printf 'LESAVKA_SERVER_RC_MODES=auto requires v4l2-ctl for local webcam mode discovery.\n' >&2
    exit 64
  fi
  python3 - <<'PY' \
    "${LESAVKA_SERVER_RC_MODE_DISCOVERY_SIZES}" \
    "${LESAVKA_SERVER_RC_MODE_DISCOVERY_FPS}" \
    "${LESAVKA_SERVER_RC_MODE_DISCOVERY_INCLUDE_REGEX}" \
    "${LESAVKA_SERVER_RC_MODE_DISCOVERY_EXCLUDE_REGEX}"
import glob
import re
import subprocess
import sys

sizes_raw, fps_raw, include_raw, exclude_raw = sys.argv[1:5]

def parse_sizes(raw):
    sizes = set()
    for entry in raw.split(","):
        entry = entry.strip()
        if not entry:
            continue
        match = re.fullmatch(r"(\d+)x(\d+)", entry)
        if not match:
            raise SystemExit(f"invalid discovery size {entry!r}; expected WIDTHxHEIGHT")
        sizes.add((int(match.group(1)), int(match.group(2))))
    return sizes

def parse_fps(raw):
    values = set()
    for entry in raw.split(","):
        entry = entry.strip()
        if not entry:
            continue
        if not entry.isdigit():
            raise SystemExit(f"invalid discovery fps {entry!r}; expected integer FPS")
        values.add(int(entry))
    return values

allowed_sizes = parse_sizes(sizes_raw)
allowed_fps = parse_fps(fps_raw)
include = re.compile(include_raw, re.IGNORECASE) if include_raw else None
exclude = re.compile(exclude_raw, re.IGNORECASE) if exclude_raw else None
all_modes = set()
camera_modes = []

for dev in sorted(glob.glob("/dev/video*")):
    try:
        info = subprocess.run(
            ["v4l2-ctl", "-d", dev, "--info"],
            check=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.DEVNULL,
            text=True,
        ).stdout
        formats = subprocess.run(
            ["v4l2-ctl", "-d", dev, "--list-formats-ext"],
            check=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.DEVNULL,
            text=True,
        ).stdout
    except Exception:
        continue

    card = dev
    for line in info.splitlines():
        if "Card type" in line:
            card = line.split(":", 1)[1].strip()
            break
    label = f"{card} {dev}"
    if exclude and exclude.search(label):
        continue
    if include and not include.search(label):
        continue

    current_size = None
    modes = set()
    for line in formats.splitlines():
        size_match = re.search(r"Size:\s+Discrete\s+(\d+)x(\d+)", line)
        if size_match:
            current_size = (int(size_match.group(1)), int(size_match.group(2)))
            continue
        fps_match = re.search(r"Interval:\s+Discrete\s+[^()]+\((\d+(?:\.\d+)?) fps\)", line)
        if not fps_match or current_size not in allowed_sizes:
            continue
        fps_float = float(fps_match.group(1))
        fps = int(round(fps_float))
        if abs(fps_float - fps) > 0.05 or fps not in allowed_fps:
            continue
        modes.add((current_size[0], current_size[1], fps))

    if modes:
        all_modes.update(modes)
        camera_modes.append((label, modes))

if not all_modes:
    print(
        "no matching local webcam modes found; "
        f"sizes={sizes_raw} fps={fps_raw} include={include_raw!r} exclude={exclude_raw!r}",
        file=sys.stderr,
    )
    raise SystemExit(64)

for label, modes in camera_modes:
    rendered = ",".join(f"{w}x{h}@{fps}" for w, h, fps in sorted(modes))
    print(f"   -> local webcam {label}: {rendered}", file=sys.stderr)

print(",".join(f"{w}x{h}@{fps}" for w, h, fps in sorted(all_modes)), end="")
PY
}

clear_remote_sudo_password() {
  LESAVKA_SERVER_RC_REMOTE_SUDO_PASSWORD=""
}
trap clear_remote_sudo_password EXIT

ensure_remote_sudo_password() {
  [[ "${LESAVKA_SERVER_RC_RECONFIGURE}" != "0" ]] || return 0
  [[ -z "${LESAVKA_SERVER_RC_RECONFIGURE_COMMAND}" ]] || return 0
  [[ -n "${LESAVKA_SERVER_RC_REMOTE_SUDO_PASSWORD}" ]] && return 0

  if [[ "${LESAVKA_SERVER_RC_PROMPT_SUDO_EARLY}" == "0" ]]; then
    printf 'remote sudo password is required for automatic reconfigure; set LESAVKA_SERVER_RC_REMOTE_SUDO_PASSWORD or leave LESAVKA_SERVER_RC_PROMPT_SUDO_EARLY=1.\n' >&2
    exit 64
  fi
  if [[ ! -t 0 ]]; then
    printf 'remote sudo password is required, but stdin is not a terminal.\n' >&2
    printf 'Re-run from a terminal or set LESAVKA_SERVER_RC_REMOTE_SUDO_PASSWORD in the environment.\n' >&2
    exit 64
  fi

  printf 'Theia sudo password for %s: ' "${LESAVKA_SERVER_HOST}" >&2
  IFS= read -r -s LESAVKA_SERVER_RC_REMOTE_SUDO_PASSWORD
  printf '\n' >&2
}

run_remote_root_script() {
  local description=$1
  shift
  local script_file remote_wrapper ssh_cmd status
  script_file="$(mktemp)"
  cat >"${script_file}"

  remote_wrapper='set -euo pipefail
read -r __lesavka_sudo_password
__lesavka_script=$(mktemp)
cleanup() { rm -f "$__lesavka_script"; }
trap cleanup EXIT
cat >"$__lesavka_script"
printf "%s\n" "$__lesavka_sudo_password" | sudo -S -p "" -v
printf "%s\n" "$__lesavka_sudo_password" | sudo -S -p "" bash "$__lesavka_script" "$@"
'
  printf -v ssh_cmd 'bash -c %q _' "${remote_wrapper}"
  for arg in "$@"; do
    printf -v ssh_cmd '%s %q' "${ssh_cmd}" "${arg}"
  done

  set +e
  {
    printf '%s\n' "${LESAVKA_SERVER_RC_REMOTE_SUDO_PASSWORD}"
    cat "${script_file}"
  } | ssh ${SSH_OPTS} "${LESAVKA_SERVER_HOST}" "${ssh_cmd}"
  status=$?
  set -e
  rm -f "${script_file}"
  if [[ "${status}" -ne 0 ]]; then
    printf '%s failed on %s with exit %s\n' "${description}" "${LESAVKA_SERVER_HOST}" "${status}" >&2
  fi
  return "${status}"
}

prime_remote_sudo() {
  [[ "${LESAVKA_SERVER_RC_RECONFIGURE}" != "0" ]] || return 0
  [[ -z "${LESAVKA_SERVER_RC_RECONFIGURE_COMMAND}" ]] || return 0
  ensure_remote_sudo_password
  echo "==> priming remote sudo on ${LESAVKA_SERVER_HOST}"
  run_remote_root_script "remote sudo prime" <<'REMOTE_SUDO_PRIME'
set -euo pipefail
true
REMOTE_SUDO_PRIME
}

sleep_start_delay() {
  [[ "${LESAVKA_SERVER_RC_START_DELAY_SECONDS}" != "0" ]] || return 0
  if [[ ! "${LESAVKA_SERVER_RC_START_DELAY_SECONDS}" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
    printf 'LESAVKA_SERVER_RC_START_DELAY_SECONDS must be a non-negative number, got %s\n' "${LESAVKA_SERVER_RC_START_DELAY_SECONDS}" >&2
    exit 64
  fi
  echo "==> delaying server-to-RC matrix start for ${LESAVKA_SERVER_RC_START_DELAY_SECONDS}s"
  echo "   ↪ remote sudo has already been primed; sleeping before prebuild/reconfigure/capture"
  sleep "${LESAVKA_SERVER_RC_START_DELAY_SECONDS}"
}

prebuild_probe_tools() {
  [[ "${LESAVKA_SERVER_RC_PROBE_PREBUILD}" != "0" ]] || return 0
  echo "==> prebuilding relay control/analyzer once for the mode matrix"
  (
    cd "${REPO_ROOT}"
    cargo build -p lesavka_client --bin lesavka-sync-analyze --bin lesavka-relayctl
  )
}

reconfigure_server_mode() {
  local mode=$1
  local width=$2
  local height=$3
  local fps=$4
  local audio_delay_us=${5:-$(lookup_audio_delay_us "${mode}")}
  local video_delay_us=${6:-$(lookup_video_delay_us "${mode}")}
  [[ "${LESAVKA_SERVER_RC_RECONFIGURE}" != "0" ]] || return 0

  echo "==> reconfiguring ${LESAVKA_SERVER_HOST} UVC gadget for ${mode}"
  if [[ -n "${LESAVKA_SERVER_RC_RECONFIGURE_COMMAND}" ]]; then
    LESAVKA_MODE="${mode}" \
    LESAVKA_UVC_WIDTH="${width}" \
    LESAVKA_UVC_HEIGHT="${height}" \
    LESAVKA_UVC_FPS="${fps}" \
    LESAVKA_SERVER_RC_PROFILE="${LESAVKA_SERVER_RC_NORMALIZED_PROFILE}" \
    LESAVKA_SERVER_RC_AUDIO_PROFILE="${LESAVKA_SERVER_RC_NORMALIZED_AUDIO_PROFILE}" \
    LESAVKA_CALIBRATION_PROFILE="${LESAVKA_SERVER_RC_CALIBRATION_PROFILE}" \
    LESAVKA_UPLINK_CAMERA_CODEC="${LESAVKA_SERVER_RC_NORMALIZED_PROFILE}" \
    LESAVKA_UPLINK_AUDIO_CODEC="${LESAVKA_SERVER_RC_NORMALIZED_AUDIO_PROFILE}" \
    LESAVKA_CAM_CODEC="${LESAVKA_SERVER_RC_NORMALIZED_PROFILE}" \
    LESAVKA_UPSTREAM_AUDIO_PLAYOUT_OFFSET_US="${audio_delay_us}" \
    LESAVKA_UPSTREAM_VIDEO_PLAYOUT_OFFSET_US="${video_delay_us}" \
    LESAVKA_UPSTREAM_AUDIO_PLAYOUT_MODE_OFFSETS_US="${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US}" \
    LESAVKA_UPSTREAM_VIDEO_PLAYOUT_MODE_OFFSETS_US="${LESAVKA_SERVER_RC_MODE_DELAYS_US}" \
    LESAVKA_UPSTREAM_HEVC_OPUS_AUDIO_PLAYOUT_MODE_OFFSETS_US="${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US}" \
    LESAVKA_UPSTREAM_HEVC_PCM_AUDIO_PLAYOUT_MODE_OFFSETS_US="${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US}" \
    LESAVKA_UPSTREAM_MJPEG_OPUS_AUDIO_PLAYOUT_MODE_OFFSETS_US="${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US}" \
    LESAVKA_UPSTREAM_MJPEG_PCM_AUDIO_PLAYOUT_MODE_OFFSETS_US="${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US}" \
      bash -c "${LESAVKA_SERVER_RC_RECONFIGURE_COMMAND}"
    return 0
  fi

  if [[ "${LESAVKA_SERVER_RC_RECONFIGURE_STRATEGY}" != "runtime" ]]; then
    printf 'unsupported LESAVKA_SERVER_RC_RECONFIGURE_STRATEGY=%s\n' "${LESAVKA_SERVER_RC_RECONFIGURE_STRATEGY}" >&2
    printf 'Use runtime for fast mode changes, or LESAVKA_SERVER_RC_RECONFIGURE_COMMAND for a custom install/reconfigure command.\n' >&2
    return 64
  fi

  local interval
  interval=$((10000000 / fps))
  run_remote_root_script "runtime UVC reconfigure for ${mode}" \
    "${mode}" \
    "${width}" \
    "${height}" \
    "${fps}" \
    "${interval}" \
    "${LESAVKA_SERVER_RC_RECONFIGURE_CODEC}" \
    "${LESAVKA_SERVER_RC_NORMALIZED_PROFILE}" \
    "${LESAVKA_SERVER_RC_NORMALIZED_AUDIO_PROFILE}" \
    "${LESAVKA_SERVER_RC_CALIBRATION_PROFILE}" \
    "${LESAVKA_SERVER_RC_ALLOW_GADGET_RESET}" \
    "${LESAVKA_SERVER_RC_FORCE_GADGET_REBUILD}" \
    "${LESAVKA_SERVER_RC_RECONFIGURE_SETTLE_SECONDS}" \
    "${LESAVKA_SERVER_RC_RECONFIGURE_VERBOSE}" \
    "${audio_delay_us}" \
    "${video_delay_us}" \
    "${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US}" \
    "${LESAVKA_SERVER_RC_MODE_DELAYS_US}" <<'REMOTE_RECONFIGURE'
set -euo pipefail
mode=$1
width=$2
height=$3
fps=$4
interval=$5
codec=$6
ingress_profile=$7
audio_profile=$8
calibration_profile=$9
allow_gadget_reset=${10}
force_gadget_rebuild=${11}
settle_seconds=${12}
verbose=${13}
audio_delay_us=${14}
video_delay_us=${15}
audio_delay_map=${16}
video_delay_map=${17}

set_env_value() {
  local file=$1
  local key=$2
  local value=$3
  local tmp
  tmp=$(mktemp)
  if [[ -f "${file}" ]]; then
    awk -v key="${key}" -v value="${value}" '
      BEGIN { wrote = 0 }
      $0 ~ "^" key "=" {
        print key "=" value
        wrote = 1
        next
      }
      { print }
      END {
        if (!wrote) {
          print key "=" value
        }
      }
    ' "${file}" >"${tmp}"
  else
    printf '%s=%s\n' "${key}" "${value}" >"${tmp}"
  fi
  install -m 0644 "${tmp}" "${file}"
  rm -f "${tmp}"
}

if [[ ! -x /usr/local/bin/lesavka-core.sh ]]; then
  printf 'missing /usr/local/bin/lesavka-core.sh; run the server installer once before using fast runtime reconfigure.\n' >&2
  exit 65
fi
if [[ ! -x /usr/local/bin/lesavka-server || ! -x /usr/local/bin/lesavka-uvc ]]; then
  printf 'missing installed Lesavka binaries; run the server installer once before using fast runtime reconfigure.\n' >&2
  exit 65
fi

install -d -m 0755 /etc/lesavka
touch /etc/lesavka/server.env /etc/lesavka/uvc.env

set_env_value /etc/lesavka/server.env LESAVKA_CAM_OUTPUT uvc
set_env_value /etc/lesavka/server.env LESAVKA_CAM_CODEC "${ingress_profile}"
set_env_value /etc/lesavka/server.env LESAVKA_UPLINK_CAMERA_CODEC "${ingress_profile}"
set_env_value /etc/lesavka/server.env LESAVKA_UPLINK_AUDIO_CODEC "${audio_profile}"
set_env_value /etc/lesavka/server.env LESAVKA_CALIBRATION_PROFILE "${calibration_profile}"
set_env_value /etc/lesavka/server.env LESAVKA_UVC_CODEC "${codec}"
set_env_value /etc/lesavka/server.env LESAVKA_UVC_WIDTH "${width}"
set_env_value /etc/lesavka/server.env LESAVKA_UVC_HEIGHT "${height}"
set_env_value /etc/lesavka/server.env LESAVKA_UVC_FPS "${fps}"
set_env_value /etc/lesavka/server.env LESAVKA_UVC_INTERVAL "${interval}"
set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_AUDIO_PLAYOUT_MODE_OFFSETS_US "${audio_delay_map}"
set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_VIDEO_PLAYOUT_MODE_OFFSETS_US "${video_delay_map}"
set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_AUDIO_PLAYOUT_OFFSET_US "${audio_delay_us}"
set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_VIDEO_PLAYOUT_OFFSET_US "${video_delay_us}"
case "${ingress_profile}" in
  hevc)
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_HEVC_AUDIO_PLAYOUT_MODE_OFFSETS_US "${audio_delay_map}"
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_HEVC_VIDEO_PLAYOUT_MODE_OFFSETS_US "${video_delay_map}"
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_HEVC_AUDIO_PLAYOUT_OFFSET_US "${audio_delay_us}"
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_HEVC_VIDEO_PLAYOUT_OFFSET_US "${video_delay_us}"
    ;;
  *)
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_MJPEG_AUDIO_PLAYOUT_MODE_OFFSETS_US "${audio_delay_map}"
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_MJPEG_VIDEO_PLAYOUT_MODE_OFFSETS_US "${video_delay_map}"
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_MJPEG_AUDIO_PLAYOUT_OFFSET_US "${audio_delay_us}"
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_MJPEG_VIDEO_PLAYOUT_OFFSET_US "${video_delay_us}"
    ;;
esac
case "${ingress_profile}+${audio_profile}" in
  hevc+opus)
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_HEVC_OPUS_AUDIO_PLAYOUT_MODE_OFFSETS_US "${audio_delay_map}"
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_HEVC_OPUS_AUDIO_PLAYOUT_OFFSET_US "${audio_delay_us}"
    ;;
  hevc+pcm)
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_HEVC_PCM_AUDIO_PLAYOUT_MODE_OFFSETS_US "${audio_delay_map}"
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_HEVC_PCM_AUDIO_PLAYOUT_OFFSET_US "${audio_delay_us}"
    ;;
  mjpeg+opus)
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_MJPEG_OPUS_AUDIO_PLAYOUT_MODE_OFFSETS_US "${audio_delay_map}"
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_MJPEG_OPUS_AUDIO_PLAYOUT_OFFSET_US "${audio_delay_us}"
    ;;
  *)
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_MJPEG_PCM_AUDIO_PLAYOUT_MODE_OFFSETS_US "${audio_delay_map}"
    set_env_value /etc/lesavka/server.env LESAVKA_UPSTREAM_MJPEG_PCM_AUDIO_PLAYOUT_OFFSET_US "${audio_delay_us}"
    ;;
esac

set_env_value /etc/lesavka/uvc.env LESAVKA_UVC_CODEC "${codec}"
set_env_value /etc/lesavka/uvc.env LESAVKA_UVC_WIDTH "${width}"
set_env_value /etc/lesavka/uvc.env LESAVKA_UVC_HEIGHT "${height}"
set_env_value /etc/lesavka/uvc.env LESAVKA_UVC_FPS "${fps}"
set_env_value /etc/lesavka/uvc.env LESAVKA_UVC_INTERVAL "${interval}"

printf '   ↪ fast runtime env updated: CAM_OUTPUT=uvc UVC_MODE=%s codec=%s\n' "${mode}" "${codec}"
systemctl daemon-reload
systemctl stop lesavka-server >/dev/null 2>&1 || true
systemctl stop lesavka-uvc >/dev/null 2>&1 || true
systemctl reset-failed lesavka-core lesavka-uvc lesavka-server >/dev/null 2>&1 || true

if [[ "${allow_gadget_reset}" != "0" && "${force_gadget_rebuild}" != "0" ]]; then
  printf '   ↪ cycling UVC gadget descriptors for %s\n' "${mode}"
  mode_log_id=$(printf '%s' "${mode}" | tr -c '[:alnum:]_.-' '_')
  core_log="/tmp/lesavka-core-reconfigure-${mode_log_id}.log"
  core_cmd=(
    env
    LESAVKA_ALLOW_GADGET_RESET=1 \
    LESAVKA_FORCE_GADGET_REBUILD=1 \
    LESAVKA_ATTACH_WRITE_UDC=1 \
    LESAVKA_DETACH_CLEAR_UDC=1 \
    LESAVKA_UVC_FALLBACK=0 \
    LESAVKA_UVC_CODEC="${codec}" \
    LESAVKA_UVC_WIDTH="${width}" \
    LESAVKA_UVC_HEIGHT="${height}" \
    LESAVKA_UVC_FPS="${fps}" \
    LESAVKA_UVC_INTERVAL="${interval}" \
    /usr/local/bin/lesavka-core.sh
  )
  if [[ "${verbose}" != "0" ]]; then
    "${core_cmd[@]}"
  else
    if "${core_cmd[@]}" >"${core_log}" 2>&1; then
      printf '   ↪ lesavka-core reconfigure log: %s\n' "${core_log}"
    else
      rc=$?
      printf 'lesavka-core reconfigure failed; tail of %s follows\n' "${core_log}" >&2
      tail -n 80 "${core_log}" >&2 || true
      exit "${rc}"
    fi
  fi
elif [[ "${allow_gadget_reset}" != "0" ]]; then
  printf '   ↪ gadget reset allowed, but force rebuild disabled; refreshing services only\n'
else
  printf '   ↪ preserving attached UVC gadget; descriptors may remain on the previous mode\n'
fi

systemctl start lesavka-uvc
systemctl restart lesavka-server
sleep "${settle_seconds}"
systemctl is-active lesavka-core lesavka-uvc lesavka-server >/dev/null
printf '   ↪ services active after %s reconfigure\n' "${mode}"
REMOTE_RECONFIGURE
}

wait_tethys_media_ready() {
  local mode=$1
  local width=$2
  local height=$3
  local fps=$4
  [[ "${LESAVKA_SERVER_RC_WAIT_TETHYS_READY}" != "0" ]] || return 0

  echo "==> waiting for Tethys media endpoints for ${mode}"
  ssh ${SSH_OPTS} "${TETHYS_HOST}" bash -s -- \
    "${mode}" \
    "${width}" \
    "${height}" \
    "${fps}" \
    "${LESAVKA_SERVER_RC_TETHYS_READY_TIMEOUT_SECONDS}" \
    "${LESAVKA_SERVER_RC_TETHYS_SETTLE_SECONDS}" \
    "${REMOTE_CAPTURE_STACK}" \
    "${REMOTE_AUDIO_SOURCE}" <<'REMOTE_TETHYS_READY'
set -euo pipefail
mode=$1
width=$2
height=$3
fps=$4
timeout_seconds=$5
settle_seconds=$6
capture_stack=$7
audio_source=$8

sleep "${settle_seconds}"

find_lesavka_video_device() {
  if [[ -d /dev/v4l/by-id ]]; then
    while IFS= read -r path; do
      [[ -e "${path}" ]] || continue
      printf '%s\n' "${path}"
      return 0
    done < <(find /dev/v4l/by-id -maxdepth 1 -type l -name '*Lesavka*video-index0' 2>/dev/null | sort)
  fi

  if command -v v4l2-ctl >/dev/null 2>&1; then
    v4l2-ctl --list-devices 2>/dev/null \
      | awk '
          BEGIN { want=0 }
          /Lesavka Composite|Lesavka.*UVC/ { want=1; next }
          /^[^ \t]/ { want=0 }
          want && /^[ \t]+\/dev\/video[0-9]+/ {
            gsub(/^[ \t]+/, "", $0)
            print
            exit
          }
        '
  fi
}

video_ready() {
  local dev=$1
  [[ -n "${dev}" ]] || return 1
  [[ -e "${dev}" ]] || return 1
  if ! command -v v4l2-ctl >/dev/null 2>&1; then
    return 0
  fi

  local listing
  listing="$(v4l2-ctl -d "${dev}" --list-formats-ext 2>/dev/null || true)"
  grep -q "Size: Discrete ${width}x${height}" <<<"${listing}" || return 1
  grep -Eq "(^|[^0-9])${fps}(\\.0+)? fps" <<<"${listing}" || return 1
}

pulse_ready() {
  if ! command -v pactl >/dev/null 2>&1; then
    return 1
  fi
  if [[ "${audio_source}" == pulse:* ]]; then
    local requested=${audio_source#pulse:}
    pactl list short sources 2>/dev/null | awk -v requested="${requested}" '$2 == requested { found=1 } END { exit found ? 0 : 1 }'
    return
  fi
  pactl list short sources 2>/dev/null | grep -Eq 'alsa_input\..*Lesavka_Composite|Lesavka_Composite'
}

alsa_ready() {
  if [[ "${audio_source}" == alsa:* ]]; then
    [[ -e "${audio_source#alsa:}" ]] || return 1
    return 0
  fi
  command -v arecord >/dev/null 2>&1 || return 1
  arecord -l 2>/dev/null | grep -Eq 'Lesavka|UAC2_Gadget|UAC2Gadget|Composite'
}

audio_ready() {
  case "${capture_stack}" in
    pulse)
      pulse_ready
      ;;
    alsa)
      alsa_ready
      ;;
    auto)
      pulse_ready || alsa_ready
      ;;
    pwpipe)
      command -v pw-dump >/dev/null 2>&1 && pw-dump 2>/dev/null | grep -Eq 'Lesavka_Composite|Lesavka Composite'
      ;;
    *)
      pulse_ready || alsa_ready
      ;;
  esac
}

deadline=$((SECONDS + timeout_seconds))
last_video='none'
last_audio='none'
while (( SECONDS <= deadline )); do
  video_dev="$(find_lesavka_video_device || true)"
  last_video="${video_dev:-none}"
  if [[ -n "${video_dev}" ]] && video_ready "${video_dev}"; then
    if audio_ready; then
      printf '   ↪ Tethys media ready: video=%s mode=%s audio_stack=%s\n' "${video_dev}" "${mode}" "${capture_stack}"
      exit 0
    fi
    last_audio='not-ready'
  fi
  sleep 0.5
done

printf 'timed out waiting for Tethys Lesavka media endpoints for %s after %ss\n' "${mode}" "${timeout_seconds}" >&2
printf 'last video candidate: %s\n' "${last_video}" >&2
printf 'last audio candidate: %s\n' "${last_audio}" >&2
if command -v v4l2-ctl >/dev/null 2>&1; then
  v4l2-ctl --list-devices >&2 || true
  if [[ "${last_video}" != "none" ]]; then
    v4l2-ctl -d "${last_video}" --list-formats-ext >&2 || true
  fi
fi
if command -v pactl >/dev/null 2>&1; then
  pactl list short sources | grep -iE 'lesavka|uac|composite' >&2 || true
fi
if command -v arecord >/dev/null 2>&1; then
  arecord -l >&2 || true
fi
exit 70
REMOTE_TETHYS_READY
}

write_mode_result() {
  local mode=$1
  local width=$2
  local height=$3
  local fps=$4
  local video_delay_us=$5
  local audio_delay_us=$6
  local run_status=$7
  local run_log=$8
  local artifact_dir=$9
  local output_json=${10}

  python3 - <<'PY' \
    "${mode}" \
    "${width}" \
    "${height}" \
    "${fps}" \
    "${video_delay_us}" \
    "${audio_delay_us}" \
    "${run_status}" \
    "${run_log}" \
    "${artifact_dir}" \
    "${output_json}" \
    "${LESAVKA_SERVER_RC_REQUIRE_SYNC_PASS}" \
    "${LESAVKA_SERVER_RC_REQUIRE_FRESHNESS_PASS}" \
    "${LESAVKA_SERVER_RC_MAX_VIDEO_HICCUPS}" \
    "${LESAVKA_SERVER_RC_MAX_AUDIO_HICCUPS}" \
    "${LESAVKA_SERVER_RC_MAX_VIDEO_P95_JITTER_MS}" \
    "${LESAVKA_SERVER_RC_MAX_AUDIO_P95_JITTER_MS}" \
    "${LESAVKA_SERVER_RC_MAX_VIDEO_MISSING_FRAMES}" \
    "${LESAVKA_SERVER_RC_MAX_VIDEO_UNDECODABLE_FRAMES}" \
    "${LESAVKA_SERVER_RC_MAX_VIDEO_DUPLICATE_FRAMES}" \
    "${LESAVKA_SERVER_RC_MAX_AUDIO_LOW_RMS_WINDOWS}" \
    "${LESAVKA_SERVER_RC_MIN_CODED_PAIRS}" \
    "${LESAVKA_SERVER_RC_REQUIRE_ALL_CODED_PAIRS}" \
    "${LESAVKA_SERVER_RC_REQUIRE_SMOOTHNESS_PASS}"
import json
import math
import pathlib
import sys

(
    mode,
    width_raw,
    height_raw,
    fps_raw,
    video_delay_raw,
    audio_delay_raw,
    run_status_raw,
    run_log,
    artifact_dir_raw,
    output_json,
    require_sync_raw,
    require_freshness_raw,
    max_video_hiccups_raw,
    max_audio_hiccups_raw,
    max_video_jitter_raw,
    max_audio_jitter_raw,
    max_missing_raw,
    max_undecodable_raw,
    max_duplicates_raw,
    max_low_rms_raw,
    min_coded_pairs_raw,
    require_all_coded_pairs_raw,
    require_smoothness_raw,
) = sys.argv[1:]


def as_bool(value):
    return str(value).strip().lower() not in {"", "0", "false", "no", "off"}


def as_int(value, default=0):
    try:
        return int(str(value).strip())
    except Exception:
        return default


def as_float(value, default=0.0):
    try:
        result = float(str(value).strip())
    except Exception:
        return default
    return result if math.isfinite(result) else default


def load_json(path):
    try:
        return json.loads(pathlib.Path(path).read_text())
    except Exception:
        return {}


def nested(mapping, *keys, default=None):
    value = mapping
    for key in keys:
        if not isinstance(value, dict):
            return default
        value = value.get(key)
    return default if value is None else value


artifact_dir = pathlib.Path(artifact_dir_raw) if artifact_dir_raw else pathlib.Path()
report = load_json(artifact_dir / "report.json")
correlation = load_json(artifact_dir / "output-delay-correlation.json")
calibration = load_json(artifact_dir / "output-delay-calibration.json")
timing_map = correlation.get("timing_map") or {}
freshness = correlation.get("freshness") or {}
capture_timebase = freshness.get("capture_timebase") or {}
smoothness = correlation.get("smoothness") or {}
event_visibility = correlation.get("event_visibility") or {}
video = smoothness.get("video") or {}
audio = smoothness.get("audio") or {}
audio_cadence = audio.get("packet_cadence") or {}
audio_rms = audio.get("rms_continuity") or {}
verdict = report.get("verdict") or {}
signature_coverage = report.get("signature_coverage") or {}

sync_pass = verdict.get("passed") is True
freshness_status = freshness.get("status", "unknown")
freshness_pass = freshness_status == "pass"
run_status = as_int(run_status_raw, 1)

video_hiccups = as_int(video.get("hiccup_count"), 0)
audio_hiccups = as_int(audio_cadence.get("hiccup_count"), 0)
video_jitter = as_float(nested(video, "jitter_stats", "p95_jitter_ms"), 0.0)
audio_jitter = as_float(nested(audio_cadence, "jitter_stats", "p95_jitter_ms"), 0.0)
missing = as_int(video.get("estimated_missing_frames"), 0)
undecodable = as_int(video.get("undecodable_frames"), 0)
duplicates = as_int(video.get("duplicate_frames"), 0)
low_rms = as_int(audio_rms.get("low_rms_window_count"), 0)
signature_expected = as_int(signature_coverage.get("expected_event_count"), 0)
signature_paired = as_int(signature_coverage.get("paired_event_count"), 0)
signature_unknown = as_int(signature_coverage.get("unknown_pair_identity_count"), 0)
min_coded_pairs = as_int(min_coded_pairs_raw, 0)
require_all_coded_pairs = as_bool(require_all_coded_pairs_raw)
require_smoothness = as_bool(require_smoothness_raw)
pair_confidences = []
for event in report.get("paired_events") or []:
    if not isinstance(event, dict):
        continue
    try:
        confidence = float(event.get("confidence"))
    except Exception:
        continue
    if math.isfinite(confidence):
        pair_confidences.append(confidence)


def median(values, default=0.0):
    if not values:
        return default
    ordered = sorted(values)
    mid = len(ordered) // 2
    if len(ordered) % 2:
        return ordered[mid]
    return (ordered[mid - 1] + ordered[mid]) / 2.0


activity_start_delta_ms = as_float(report.get("activity_start_delta_ms"), 0.0)
first_skew_ms = as_float(report.get("first_skew_ms"), 0.0)
activity_pair_disagreement_ms = (
    activity_start_delta_ms - first_skew_ms
    if as_int(report.get("paired_event_count"), 0) > 0
    else 0.0
)

reasons = []
smoothness_warnings = []
if run_status != 0:
    reasons.append(f"probe command exited {run_status}")
if as_bool(require_sync_raw) and not sync_pass:
    reasons.append(f"sync did not pass: {verdict.get('status', 'unknown')}")
if as_bool(require_freshness_raw) and not freshness_pass:
    reasons.append(f"freshness did not pass: {freshness_status}")
if capture_timebase and capture_timebase.get("valid") is False:
    reasons.append(
        "capture timebase invalid: "
        f"{capture_timebase.get('reason', capture_timebase.get('status', 'invalid'))}"
    )
if signature_expected > 0:
    if require_all_coded_pairs and signature_paired < signature_expected:
        reasons.append(f"paired coded signatures {signature_paired} < expected {signature_expected}")
    elif min_coded_pairs > 0 and signature_paired < min_coded_pairs:
        reasons.append(f"paired coded signatures {signature_paired} < required {min_coded_pairs}")
    if signature_unknown > 0:
        reasons.append(f"paired signatures without coded identity {signature_unknown} > 0")
elif report.get("coded_events") is True:
    reasons.append("coded signature coverage unavailable")
if video_hiccups > as_int(max_video_hiccups_raw):
    smoothness_warnings.append(f"video hiccups {video_hiccups} > {max_video_hiccups_raw}")
if audio_hiccups > as_int(max_audio_hiccups_raw):
    smoothness_warnings.append(f"audio hiccups {audio_hiccups} > {max_audio_hiccups_raw}")
if video_jitter > as_float(max_video_jitter_raw):
    smoothness_warnings.append(f"video p95 jitter {video_jitter:.1f}ms > {as_float(max_video_jitter_raw):.1f}ms")
if audio_jitter > as_float(max_audio_jitter_raw):
    smoothness_warnings.append(f"audio p95 jitter {audio_jitter:.1f}ms > {as_float(max_audio_jitter_raw):.1f}ms")
if missing > as_int(max_missing_raw):
    smoothness_warnings.append(f"estimated missing video frames {missing} > {max_missing_raw}")
if undecodable > as_int(max_undecodable_raw):
    smoothness_warnings.append(f"undecodable video frames {undecodable} > {max_undecodable_raw}")
if duplicates > as_int(max_duplicates_raw):
    smoothness_warnings.append(f"duplicate video frames {duplicates} > {max_duplicates_raw}")
if low_rms > as_int(max_low_rms_raw):
    smoothness_warnings.append(f"low-RMS audio windows {low_rms} > {max_low_rms_raw}")
if require_smoothness:
    reasons.extend(smoothness_warnings)

artifact = {
    "schema": "lesavka.server-rc-mode-result.v1",
    "mode": mode,
    "width": as_int(width_raw),
    "height": as_int(height_raw),
    "fps": as_int(fps_raw),
    "audio_delay_us": as_int(audio_delay_raw),
    "video_delay_us": as_int(video_delay_raw),
    "run_status": run_status,
    "run_log": run_log,
    "artifact_dir": str(artifact_dir),
    "report_json": str(artifact_dir / "report.json"),
    "correlation_json": str(artifact_dir / "output-delay-correlation.json"),
    "calibration_json": str(artifact_dir / "output-delay-calibration.json"),
    "timing_map": timing_map,
    "passed": not reasons,
    "failure_reasons": reasons,
    "smoothness_required": require_smoothness,
    "smoothness_warnings": smoothness_warnings,
    "event_visibility": event_visibility,
    "sync": {
        "passed": sync_pass,
        "status": verdict.get("status", "unknown"),
        "reason": verdict.get("reason", ""),
        "p95_abs_skew_ms": as_float(verdict.get("p95_abs_skew_ms"), 0.0),
        "median_skew_ms": as_float(report.get("median_skew_ms"), 0.0),
        "drift_ms": as_float(report.get("drift_ms"), 0.0),
        "activity_start_delta_ms": activity_start_delta_ms,
        "first_skew_ms": first_skew_ms,
        "activity_pair_disagreement_ms": activity_pair_disagreement_ms,
        "video_event_count": as_int(report.get("video_event_count"), 0),
        "audio_event_count": as_int(report.get("audio_event_count"), 0),
        "paired_event_count": as_int(report.get("paired_event_count"), 0),
        "signature_expected_event_count": signature_expected,
        "signature_paired_event_count": signature_paired,
        "signature_missing_event_ids": signature_coverage.get("missing_event_ids") or [],
        "signature_missing_codes": signature_coverage.get("missing_codes") or [],
        "signature_unknown_pair_identity_count": signature_unknown,
        "paired_confidence_min": min(pair_confidences) if pair_confidences else 0.0,
        "paired_confidence_median": median(pair_confidences),
    },
    "freshness": {
        "status": freshness_status,
        "reason": freshness.get("reason", ""),
        "worst_event_age_p95_ms": freshness.get("worst_event_age_p95_ms"),
        "worst_p95_pipeline_freshness_ms": freshness.get("worst_p95_pipeline_freshness_ms"),
        "minimum_pipeline_freshness_ms": freshness.get("minimum_pipeline_freshness_ms"),
        "clock_uncertainty_ms": freshness.get("clock_uncertainty_ms"),
        "worst_event_age_with_uncertainty_ms": freshness.get("worst_event_age_with_uncertainty_ms"),
        "worst_freshness_drift_ms": freshness.get("worst_freshness_drift_ms"),
        "max_age_limit_ms": freshness.get("max_age_limit_ms"),
        "capture_timebase_status": capture_timebase.get("status"),
        "capture_timebase_valid": capture_timebase.get("valid"),
        "capture_timebase_reason": capture_timebase.get("reason"),
    },
    "smoothness": {
        "video_frames": as_int(video.get("timestamps"), 0),
        "video_p95_jitter_ms": video_jitter,
        "video_max_interval_ms": as_float(nested(video, "interval_stats", "max_interval_ms"), 0.0),
        "video_hiccups": video_hiccups,
        "video_decoded_frames": as_int(video.get("decoded_frames"), 0),
        "video_duplicate_frames": duplicates,
        "video_estimated_missing_frames": missing,
        "video_undecodable_frames": undecodable,
        "audio_packets": as_int(audio_cadence.get("timestamps"), 0),
        "audio_p95_jitter_ms": audio_jitter,
        "audio_max_interval_ms": as_float(nested(audio_cadence, "interval_stats", "max_interval_ms"), 0.0),
        "audio_hiccups": audio_hiccups,
        "audio_low_rms_windows": low_rms,
        "audio_median_rms": as_float(nested(audio_rms, "rms_stats", "median_rms"), 0.0),
    },
    "output_delay_calibration": {
        "ready": calibration.get("ready") is True,
        "decision": calibration.get("decision", "unknown"),
        "target": calibration.get("target", ""),
        "paired_event_count": as_int(calibration.get("paired_event_count"), 0),
        "min_pairs": as_int(calibration.get("min_pairs"), 0),
        "measured_device_skew_ms": as_float(calibration.get("measured_device_skew_ms"), 0.0),
        "p95_abs_skew_ms": as_float(calibration.get("p95_abs_skew_ms"), 0.0),
        "max_abs_skew_ms": as_float(calibration.get("max_abs_skew_ms"), 0.0),
        "drift_ms": as_float(calibration.get("drift_ms"), 0.0),
        "active_audio_offset_us": as_int(calibration.get("active_audio_offset_us"), as_int(audio_delay_raw)),
        "active_video_offset_us": as_int(calibration.get("active_video_offset_us"), as_int(video_delay_raw)),
        "audio_offset_adjust_us": as_int(calibration.get("audio_offset_adjust_us"), 0),
        "video_offset_adjust_us": as_int(calibration.get("video_offset_adjust_us"), 0),
        "audio_target_offset_us": as_int(calibration.get("audio_target_offset_us"), 0),
        "video_target_offset_us": as_int(calibration.get("video_target_offset_us"), 0),
        "raw_device_delta_us": as_int(calibration.get("raw_device_delta_us"), 0),
        "bounded_device_delta_us": as_int(calibration.get("bounded_device_delta_us"), 0),
        "max_step_us": as_int(calibration.get("max_step_us"), 0),
        "note": calibration.get("note", ""),
    },
}
pathlib.Path(output_json).write_text(json.dumps(artifact, indent=2, sort_keys=True) + "\n")
PY
}

annotate_mode_result() {
  local output_json=$1
  local mode_id=$2
  local mode_run_index=$3
  local repeat_index=$4
  local repeat_count=$5
  local matrix_sequence=$6
  local phase=$7

  python3 - <<'PY' \
    "${output_json}" \
    "${mode_id}" \
    "${mode_run_index}" \
    "${repeat_index}" \
    "${repeat_count}" \
    "${matrix_sequence}" \
    "${phase}"
import json
import pathlib
import sys

(
    output_json_raw,
    mode_id,
    mode_run_index_raw,
    repeat_index_raw,
    repeat_count_raw,
    matrix_sequence_raw,
    phase,
) = sys.argv[1:]


def as_int(value, default=0):
    try:
        return int(str(value).strip())
    except Exception:
        return default


path = pathlib.Path(output_json_raw)
result = json.loads(path.read_text())
result.update(
    {
        "mode_id": mode_id,
        "mode_run_index": as_int(mode_run_index_raw),
        "repeat_index": as_int(repeat_index_raw),
        "repeat_count": as_int(repeat_count_raw),
        "matrix_sequence": as_int(matrix_sequence_raw),
        "probe_phase": phase,
    }
)
path.write_text(json.dumps(result, indent=2, sort_keys=True) + "\n")
PY
}

summarize_matrix() {
  python3 - <<'PY' "${MATRIX_REPORT_DIR}" "${MATRIX_SUMMARY_JSON}" "${MATRIX_SUMMARY_CSV}" "${MATRIX_SUMMARY_TXT}" "${MATRIX_DELAY_JSON}" "${MATRIX_DELAY_ENV}" "${MATRIX_STATIC_JSON}" "${MATRIX_STATIC_CSV}" "${MATRIX_STATIC_TXT}" "${MATRIX_STATIC_ENV}" "${LESAVKA_SERVER_RC_STATIC_MIN_RUNS}" "${LESAVKA_SERVER_RC_STATIC_MAX_SPREAD_US}" "${LESAVKA_SERVER_RC_STATIC_MAX_P95_SKEW_MS}" "${LESAVKA_SERVER_RC_STATIC_MAX_MEDIAN_SKEW_MS}" "${LESAVKA_SERVER_RC_STATIC_REQUIRE_FRESHNESS}" "${LESAVKA_SERVER_RC_STATIC_REQUIRE_SMOOTHNESS}"
import csv
import json
import pathlib
import shlex
import sys

root = pathlib.Path(sys.argv[1])
summary_json = pathlib.Path(sys.argv[2])
summary_csv = pathlib.Path(sys.argv[3])
summary_txt = pathlib.Path(sys.argv[4])
delay_json = pathlib.Path(sys.argv[5])
delay_env = pathlib.Path(sys.argv[6])
static_json = pathlib.Path(sys.argv[7])
static_csv = pathlib.Path(sys.argv[8])
static_txt = pathlib.Path(sys.argv[9])
static_env = pathlib.Path(sys.argv[10])
static_min_runs = int(sys.argv[11])
static_max_spread_us = int(sys.argv[12])
static_max_p95_skew_ms = float(sys.argv[13])
static_max_median_skew_ms = float(sys.argv[14])
static_require_freshness = sys.argv[15].strip().lower() not in {"", "0", "false", "no", "off"}
static_require_smoothness = sys.argv[16].strip().lower() not in {"", "0", "false", "no", "off"}


def as_int(value, default=0):
    try:
        return int(str(value).strip())
    except Exception:
        return default


def as_float(value, default=0.0):
    try:
        return float(str(value).strip())
    except Exception:
        return default


def median(values, default=None):
    cleaned = sorted(value for value in values if value is not None)
    if not cleaned:
        return default
    mid = len(cleaned) // 2
    if len(cleaned) % 2:
        return cleaned[mid]
    return (cleaned[mid - 1] + cleaned[mid]) / 2.0


def median_int(values, default=None):
    value = median(values, default)
    if value is None:
        return None
    return int(round(value))


results = []
for path in sorted(root.glob("*/mode-result.json")):
    try:
        result = json.loads(path.read_text())
        seed_path = path.with_name("mode-result-seed.json")
        tuned_path = path.with_name("mode-result-tuned.json")
        if seed_path.exists():
            result["seed_result_json"] = str(seed_path)
            try:
                seed = json.loads(seed_path.read_text())
                result["seed_audio_delay_us"] = seed.get("audio_delay_us")
                result["seed_video_delay_us"] = seed.get("video_delay_us")
            except Exception:
                pass
        if tuned_path.exists():
            result["tuned_result_json"] = str(tuned_path)
        result["result_json"] = str(path)
        results.append(result)
    except Exception:
        continue
results.sort(
    key=lambda item: (
        item.get("mode") or "",
        as_int(item.get("mode_run_index"), as_int(item.get("matrix_sequence"), 0)),
        as_int(item.get("matrix_sequence"), 0),
    )
)

mode_groups = {}
for result in results:
    mode = result.get("mode")
    if not mode:
        continue
    mode_groups.setdefault(mode, []).append(result)


def static_eligibility(result):
    sync = result.get("sync") or {}
    freshness = result.get("freshness") or {}
    calibration = result.get("output_delay_calibration") or {}
    reasons = []
    required_pairs = as_int(calibration.get("min_pairs"), 13) or 13
    if result.get("passed") is not True:
        reasons.append("probe did not pass all required gates")
    if sync.get("passed") is not True:
        reasons.append(f"sync did not pass ({sync.get('status', 'unknown')})")
    if as_int(sync.get("paired_event_count"), 0) < required_pairs:
        reasons.append(f"paired events {sync.get('paired_event_count', 0)} < {required_pairs}")
    if as_float(sync.get("p95_abs_skew_ms"), 0.0) > static_max_p95_skew_ms:
        reasons.append(
            f"p95 skew {as_float(sync.get('p95_abs_skew_ms'), 0.0):.1f}ms > {static_max_p95_skew_ms:.1f}ms"
        )
    if abs(as_float(sync.get("median_skew_ms"), 0.0)) > static_max_median_skew_ms:
        reasons.append(
            f"median skew {as_float(sync.get('median_skew_ms'), 0.0):+.1f}ms outside +/-{static_max_median_skew_ms:.1f}ms"
        )
    if static_require_freshness and freshness.get("status") != "pass":
        reasons.append(f"freshness did not pass ({freshness.get('status', 'unknown')})")
    if static_require_smoothness and result.get("smoothness_warnings"):
        reasons.append("smoothness warnings present")
    if not isinstance(result.get("video_delay_us"), int) or not isinstance(result.get("audio_delay_us"), int):
        reasons.append("tested delay values unavailable")
    return reasons


static_modes = {}
delay_recommendations = {}
video_delay_entries = []
audio_delay_entries = []
static_video_entries = []
static_audio_entries = []
for mode, mode_results in sorted(mode_groups.items()):
    eligible = []
    rejected = []
    for result in mode_results:
        reasons = static_eligibility(result)
        if reasons:
            rejected.append(
                {
                    "mode_run_index": result.get("mode_run_index"),
                    "artifact_dir": result.get("artifact_dir"),
                    "reasons": reasons,
                    "tested_video_delay_us": result.get("video_delay_us"),
                    "tested_audio_delay_us": result.get("audio_delay_us"),
                    "p95_abs_skew_ms": (result.get("sync") or {}).get("p95_abs_skew_ms"),
                    "median_skew_ms": (result.get("sync") or {}).get("median_skew_ms"),
                }
            )
        else:
            eligible.append(result)

    tested_video = [result.get("video_delay_us") for result in eligible]
    tested_audio = [result.get("audio_delay_us") for result in eligible]
    target_video = [
        (result.get("output_delay_calibration") or {}).get("video_target_offset_us")
        for result in eligible
        if isinstance((result.get("output_delay_calibration") or {}).get("video_target_offset_us"), int)
    ]
    target_audio = [
        (result.get("output_delay_calibration") or {}).get("audio_target_offset_us")
        for result in eligible
        if isinstance((result.get("output_delay_calibration") or {}).get("audio_target_offset_us"), int)
    ]
    tested_video_spread = (max(tested_video) - min(tested_video)) if tested_video else None
    tested_audio_spread = (max(tested_audio) - min(tested_audio)) if tested_audio else None
    target_video_spread = (max(target_video) - min(target_video)) if target_video else None
    recommended_video = median_int(tested_video)
    recommended_audio = median_int(tested_audio)
    status_reasons = []
    if len(eligible) < static_min_runs:
        status_reasons.append(f"eligible runs {len(eligible)} < {static_min_runs}")
    if tested_video_spread is not None and tested_video_spread > static_max_spread_us:
        status_reasons.append(f"tested video delay spread {tested_video_spread}us > {static_max_spread_us}us")
    if tested_audio_spread is not None and tested_audio_spread > static_max_spread_us:
        status_reasons.append(f"tested audio delay spread {tested_audio_spread}us > {static_max_spread_us}us")
    if recommended_video is None or recommended_audio is None:
        status_reasons.append("no recommended delay could be derived")
    if len(eligible) < static_min_runs:
        status = "needs_more_runs"
    elif status_reasons:
        status = "unstable"
    else:
        status = "ready"

    p95_values = [as_float((result.get("sync") or {}).get("p95_abs_skew_ms"), 0.0) for result in eligible]
    median_skews = [as_float((result.get("sync") or {}).get("median_skew_ms"), 0.0) for result in eligible]
    freshness_budgets = [
        as_float((result.get("freshness") or {}).get("worst_event_age_with_uncertainty_ms"), 0.0)
        for result in eligible
    ]
    static_entry = {
        "status": status,
        "ready": status == "ready",
        "reasons": status_reasons,
        "mode": mode,
        "total_runs": len(mode_results),
        "eligible_runs": len(eligible),
        "rejected_runs": rejected,
        "recommended_video_delay_us": recommended_video,
        "recommended_audio_delay_us": recommended_audio,
        "tested_video_delay_us": tested_video,
        "tested_audio_delay_us": tested_audio,
        "tested_video_delay_min_us": min(tested_video) if tested_video else None,
        "tested_video_delay_max_us": max(tested_video) if tested_video else None,
        "tested_video_delay_spread_us": tested_video_spread,
        "tested_audio_delay_spread_us": tested_audio_spread,
        "target_video_delay_us": target_video,
        "target_audio_delay_us": target_audio,
        "target_video_delay_median_us": median_int(target_video),
        "target_audio_delay_median_us": median_int(target_audio),
        "target_video_delay_spread_us": target_video_spread,
        "sync_p95_abs_skew_ms_max": max(p95_values) if p95_values else None,
        "sync_p95_abs_skew_ms_median": median(p95_values),
        "sync_abs_median_skew_ms_max": max((abs(value) for value in median_skews), default=None),
        "freshness_budget_ms_max": max(freshness_budgets) if freshness_budgets else None,
        "eligible_artifact_dirs": [result.get("artifact_dir") for result in eligible],
        "eligible_result_json": [result.get("result_json") for result in eligible],
    }
    static_modes[mode] = static_entry

    if status == "ready" and isinstance(recommended_video, int) and isinstance(recommended_audio, int):
        static_video_entries.append(f"{mode}={recommended_video}")
        static_audio_entries.append(f"{mode}={recommended_audio}")

    delay_video = recommended_video
    delay_audio = recommended_audio
    recommendation_status = "static_ready" if status == "ready" else status
    if status != "ready":
        fallback = (eligible or mode_results)[-1]
        fallback_calibration = fallback.get("output_delay_calibration") or {}
        fallback_video_target = fallback_calibration.get("video_target_offset_us")
        fallback_audio_target = fallback_calibration.get("audio_target_offset_us")
        if not isinstance(delay_video, int) or not isinstance(delay_audio, int):
            if (
                fallback_calibration.get("ready") is True
                and isinstance(fallback_video_target, int)
                and isinstance(fallback_audio_target, int)
            ):
                delay_video = fallback_video_target
                delay_audio = fallback_audio_target
                recommendation_status = "candidate_unconfirmed"
            else:
                delay_video = fallback.get("video_delay_us")
                delay_audio = fallback.get("audio_delay_us")
                recommendation_status = "tested_unstable"
        else:
            recommendation_status = f"candidate_{status}"
    if isinstance(delay_video, int) and isinstance(delay_audio, int):
        video_delay_entries.append(f"{mode}={delay_video}")
        audio_delay_entries.append(f"{mode}={delay_audio}")
    delay_recommendations[mode] = {
        "status": recommendation_status,
        "static_status": status,
        "audio_delay_us": delay_audio,
        "video_delay_us": delay_video,
        "eligible_runs": len(eligible),
        "total_runs": len(mode_results),
        "tested_video_delay_spread_us": tested_video_spread,
        "sync_p95_abs_skew_ms_max": static_entry["sync_p95_abs_skew_ms_max"],
        "sync_abs_median_skew_ms_max": static_entry["sync_abs_median_skew_ms_max"],
        "freshness_budget_ms_max": static_entry["freshness_budget_ms_max"],
        "reasons": status_reasons,
    }

summary = {
    "schema": "lesavka.server-rc-mode-matrix-summary.v1",
    "artifact_dir": str(root),
    "passed": bool(results) and all(result.get("passed") for result in results),
    "mode_count": len(results),
    "delay_recommendations_json": str(delay_json),
    "delay_recommendations_env": str(delay_env),
    "static_calibration_json": str(static_json),
    "static_calibration_csv": str(static_csv),
    "static_calibration_txt": str(static_txt),
    "static_calibration_env": str(static_env),
    "static_ready": bool(static_modes) and all(entry.get("ready") for entry in static_modes.values()),
    "static_calibration": static_modes,
    "delay_recommendations": delay_recommendations,
    "results": results,
}
summary_json.write_text(json.dumps(summary, indent=2, sort_keys=True) + "\n")
delay_json.write_text(
    json.dumps(
        {
            "schema": "lesavka.server-rc-mode-delay-recommendations.v1",
            "artifact_dir": str(root),
            "video_delays_us": {
                mode: entry.get("video_delay_us")
                for mode, entry in delay_recommendations.items()
            },
            "audio_delays_us": {
                mode: entry.get("audio_delay_us")
                for mode, entry in delay_recommendations.items()
            },
            "recommendations": delay_recommendations,
        },
        indent=2,
        sort_keys=True,
    )
    + "\n"
)
static_json.write_text(
    json.dumps(
        {
            "schema": "lesavka.server-rc-static-calibration.v1",
            "artifact_dir": str(root),
            "ready": summary["static_ready"],
            "criteria": {
                "min_runs": static_min_runs,
                "max_spread_us": static_max_spread_us,
                "max_p95_skew_ms": static_max_p95_skew_ms,
                "max_median_skew_ms": static_max_median_skew_ms,
                "require_freshness": static_require_freshness,
                "require_smoothness": static_require_smoothness,
            },
            "video_delays_us": {
                mode: entry.get("recommended_video_delay_us")
                for mode, entry in static_modes.items()
                if entry.get("ready")
            },
            "audio_delays_us": {
                mode: entry.get("recommended_audio_delay_us")
                for mode, entry in static_modes.items()
                if entry.get("ready")
            },
            "modes": static_modes,
        },
        indent=2,
        sort_keys=True,
    )
    + "\n"
)
delay_env.write_text(
    "LESAVKA_SERVER_RC_MODE_DELAYS_US="
    + shlex.quote(",".join(video_delay_entries))
    + "\n"
    + "LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US="
    + shlex.quote(",".join(audio_delay_entries))
    + "\n"
)
static_env.write_text(
    "LESAVKA_SERVER_RC_MODE_DELAYS_US="
    + shlex.quote(",".join(static_video_entries))
    + "\n"
    + "LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US="
    + shlex.quote(",".join(static_audio_entries))
    + "\n"
)

fieldnames = [
    "mode",
    "mode_run_index",
    "repeat_index",
    "matrix_sequence",
    "passed",
    "seed_video_delay_us",
    "seed_audio_delay_us",
    "video_delay_us",
    "audio_delay_us",
    "sync_status",
    "p95_abs_skew_ms",
    "median_skew_ms",
    "sync_drift_ms",
    "freshness_status",
    "freshness_budget_ms",
    "freshness_drift_ms",
    "capture_timebase_status",
    "video_hiccups",
    "video_missing",
    "video_undecodable",
    "audio_hiccups",
    "audio_low_rms",
    "calibration_ready",
    "calibration_decision",
    "calibration_target",
    "calibration_measured_skew_ms",
    "calibration_video_target_offset_us",
    "calibration_audio_target_offset_us",
    "artifact_dir",
    "result_json",
]
with summary_csv.open("w", newline="", encoding="utf-8") as handle:
    writer = csv.DictWriter(handle, fieldnames=fieldnames)
    writer.writeheader()
    for result in results:
        writer.writerow({
            "mode": result.get("mode"),
            "mode_run_index": result.get("mode_run_index"),
            "repeat_index": result.get("repeat_index"),
            "matrix_sequence": result.get("matrix_sequence"),
            "passed": result.get("passed"),
            "seed_video_delay_us": result.get("seed_video_delay_us"),
            "seed_audio_delay_us": result.get("seed_audio_delay_us"),
            "video_delay_us": result.get("video_delay_us"),
            "audio_delay_us": result.get("audio_delay_us"),
            "sync_status": (result.get("sync") or {}).get("status"),
            "p95_abs_skew_ms": (result.get("sync") or {}).get("p95_abs_skew_ms"),
            "median_skew_ms": (result.get("sync") or {}).get("median_skew_ms"),
            "sync_drift_ms": (result.get("sync") or {}).get("drift_ms"),
            "freshness_status": (result.get("freshness") or {}).get("status"),
            "freshness_budget_ms": (result.get("freshness") or {}).get("worst_event_age_with_uncertainty_ms"),
            "freshness_drift_ms": (result.get("freshness") or {}).get("worst_freshness_drift_ms"),
            "capture_timebase_status": (result.get("freshness") or {}).get("capture_timebase_status"),
            "video_hiccups": (result.get("smoothness") or {}).get("video_hiccups"),
            "video_missing": (result.get("smoothness") or {}).get("video_estimated_missing_frames"),
            "video_undecodable": (result.get("smoothness") or {}).get("video_undecodable_frames"),
            "audio_hiccups": (result.get("smoothness") or {}).get("audio_hiccups"),
            "audio_low_rms": (result.get("smoothness") or {}).get("audio_low_rms_windows"),
            "calibration_ready": (result.get("output_delay_calibration") or {}).get("ready"),
            "calibration_decision": (result.get("output_delay_calibration") or {}).get("decision"),
            "calibration_target": (result.get("output_delay_calibration") or {}).get("target"),
            "calibration_measured_skew_ms": (result.get("output_delay_calibration") or {}).get("measured_device_skew_ms"),
            "calibration_video_target_offset_us": (result.get("output_delay_calibration") or {}).get("video_target_offset_us"),
            "calibration_audio_target_offset_us": (result.get("output_delay_calibration") or {}).get("audio_target_offset_us"),
            "artifact_dir": result.get("artifact_dir"),
            "result_json": result.get("result_json"),
        })

static_fieldnames = [
    "mode",
    "status",
    "ready",
    "eligible_runs",
    "total_runs",
    "recommended_video_delay_us",
    "recommended_audio_delay_us",
    "tested_video_delay_min_us",
    "tested_video_delay_max_us",
    "tested_video_delay_spread_us",
    "target_video_delay_median_us",
    "target_video_delay_spread_us",
    "sync_p95_abs_skew_ms_max",
    "sync_p95_abs_skew_ms_median",
    "sync_abs_median_skew_ms_max",
    "freshness_budget_ms_max",
    "reasons",
]
with static_csv.open("w", newline="", encoding="utf-8") as handle:
    writer = csv.DictWriter(handle, fieldnames=static_fieldnames)
    writer.writeheader()
    for mode, entry in sorted(static_modes.items()):
        writer.writerow(
            {
                "mode": mode,
                "status": entry.get("status"),
                "ready": entry.get("ready"),
                "eligible_runs": entry.get("eligible_runs"),
                "total_runs": entry.get("total_runs"),
                "recommended_video_delay_us": entry.get("recommended_video_delay_us"),
                "recommended_audio_delay_us": entry.get("recommended_audio_delay_us"),
                "tested_video_delay_min_us": entry.get("tested_video_delay_min_us"),
                "tested_video_delay_max_us": entry.get("tested_video_delay_max_us"),
                "tested_video_delay_spread_us": entry.get("tested_video_delay_spread_us"),
                "target_video_delay_median_us": entry.get("target_video_delay_median_us"),
                "target_video_delay_spread_us": entry.get("target_video_delay_spread_us"),
                "sync_p95_abs_skew_ms_max": entry.get("sync_p95_abs_skew_ms_max"),
                "sync_p95_abs_skew_ms_median": entry.get("sync_p95_abs_skew_ms_median"),
                "sync_abs_median_skew_ms_max": entry.get("sync_abs_median_skew_ms_max"),
                "freshness_budget_ms_max": entry.get("freshness_budget_ms_max"),
                "reasons": "; ".join(entry.get("reasons") or []),
            }
        )

lines = [
    f"Server-to-RC mode matrix for {root}",
    f"- runs: {len(results)}",
    f"- unique modes: {len(mode_groups)}",
    f"- verdict: {'pass' if summary['passed'] else 'fail'}",
    f"- static calibration: {'ready' if summary['static_ready'] else 'needs-more-data'}",
]
for result in results:
    sync = result.get("sync") or {}
    freshness = result.get("freshness") or {}
    smooth = result.get("smoothness") or {}
    calibration = result.get("output_delay_calibration") or {}
    marker = "PASS" if result.get("passed") else "FAIL"
    lines.append(
        f"- {marker} {result.get('mode')} run={result.get('mode_run_index', '?')}: "
        f"delays video={result.get('video_delay_us', 0)}us audio={result.get('audio_delay_us', 0)}us; "
        f"sync {sync.get('status')} p95={sync.get('p95_abs_skew_ms', 0.0):.1f}ms median={sync.get('median_skew_ms', 0.0):+.1f}ms; "
        f"freshness {freshness.get('status')} budget={freshness.get('worst_event_age_with_uncertainty_ms') or 0.0:.1f}ms; "
        f"smooth video hiccups={smooth.get('video_hiccups', 0)} missing={smooth.get('video_estimated_missing_frames', 0)} undecodable={smooth.get('video_undecodable_frames', 0)} audio hiccups={smooth.get('audio_hiccups', 0)}"
    )
    lines.append(
        "  calibration: "
        f"{calibration.get('decision', 'unknown')} ready={calibration.get('ready', False)} "
        f"target={calibration.get('target', '')} measured={calibration.get('measured_device_skew_ms', 0.0):+.1f}ms "
        f"video_target={calibration.get('video_target_offset_us', 0)}us "
        f"audio_target={calibration.get('audio_target_offset_us', 0)}us"
    )
    lines.append(
        "  sync evidence: "
        f"video_onsets={sync.get('video_event_count', 0)} audio_onsets={sync.get('audio_event_count', 0)} "
        f"pairs={sync.get('paired_event_count', 0)} "
        f"coded_pairs={sync.get('signature_paired_event_count', 0)}/{sync.get('signature_expected_event_count', 0)} "
        f"missing_codes={sync.get('signature_missing_codes') or []} "
        f"unknown_identity={sync.get('signature_unknown_pair_identity_count', 0)} "
        f"pair_conf_median={sync.get('paired_confidence_median', 0.0):.3f} "
        f"raw_pair_disagreement={sync.get('activity_pair_disagreement_ms', 0.0):+.1f}ms"
    )
    visibility = result.get("event_visibility") or {}
    visibility_summary = visibility.get("summary") or {}
    if visibility_summary:
        lines.append(
            "  coded visibility: "
            f"paired={visibility_summary.get('paired', 0)} "
            f"video_only={visibility_summary.get('video_only', 0)} "
            f"audio_only={visibility_summary.get('audio_only', 0)} "
            f"unpaired={visibility_summary.get('unpaired', 0)} "
            f"missing={visibility_summary.get('missing', 0)}"
        )
    if freshness.get("capture_timebase_status"):
        lines.append(
            "  capture timing: "
            f"{freshness.get('capture_timebase_status')} "
            f"valid={freshness.get('capture_timebase_valid')} "
            f"reason={freshness.get('capture_timebase_reason', '')}"
        )
    signal_readiness = result.get("signal_readiness") or {}
    signal_attempts = signal_readiness.get("attempts") or []
    if signal_readiness:
        lines.append(
            "  signal readiness: "
            f"passed={signal_readiness.get('passed', False)} "
            f"attempts={len(signal_attempts)} "
            f"reason={signal_readiness.get('reason', '')}"
        )
    for attempt in signal_attempts:
        counts = attempt.get("counts") or {}
        layers = attempt.get("layers") or {}
        lines.append(
            "  signal attempt "
            f"{attempt.get('attempt', '?')}: passed={attempt.get('passed', False)} "
            f"server_events={counts.get('server_events', 0)} "
            f"video={counts.get('video_events', 0)} audio={counts.get('audio_events', 0)} "
            f"paired={counts.get('paired_events', counts.get('coded_pairs', 0))} "
            f"audio_ready={layers.get('tethys_audio_ready', False)} "
            f"video_ready={layers.get('tethys_video_ready', False)} "
            f"reason={attempt.get('reason', '')}"
        )
    if "seed_video_delay_us" in result or "seed_audio_delay_us" in result:
        lines.append(
            "  tuning: "
            f"seed video={result.get('seed_video_delay_us', 0)}us audio={result.get('seed_audio_delay_us', 0)}us -> "
            f"tested video={result.get('video_delay_us', 0)}us audio={result.get('audio_delay_us', 0)}us"
        )
    for reason in result.get("failure_reasons") or []:
        lines.append(f"  reason: {reason}")
    for warning in result.get("smoothness_warnings") or []:
        lines.append(f"  smoothness warning: {warning}")
if video_delay_entries or audio_delay_entries:
    lines.append(f"- recommended video delays: {','.join(video_delay_entries)}")
    lines.append(f"- recommended audio delays: {','.join(audio_delay_entries)}")
static_lines = [
    f"Server-to-RC static calibration for {root}",
    f"- verdict: {'ready' if summary['static_ready'] else 'needs-more-data'}",
    (
        "- criteria: "
        f"min_runs={static_min_runs} "
        f"max_spread_us={static_max_spread_us} "
        f"max_p95_skew_ms={static_max_p95_skew_ms:.1f} "
        f"max_median_skew_ms={static_max_median_skew_ms:.1f} "
        f"require_freshness={static_require_freshness} "
        f"require_smoothness={static_require_smoothness}"
    ),
]
for mode, entry in sorted(static_modes.items()):
    marker = "READY" if entry.get("ready") else "HOLD"
    reasons = "; ".join(entry.get("reasons") or [])
    if not reasons and entry.get("ready"):
        reasons = "all stability criteria met"
    static_lines.append(
        f"- {marker} {mode}: "
        f"runs={entry.get('eligible_runs')}/{entry.get('total_runs')} "
        f"video={entry.get('recommended_video_delay_us')}us "
        f"audio={entry.get('recommended_audio_delay_us')}us "
        f"spread={entry.get('tested_video_delay_spread_us')}us "
        f"p95_max={entry.get('sync_p95_abs_skew_ms_max') or 0.0:.1f}ms "
        f"median_abs_max={entry.get('sync_abs_median_skew_ms_max') or 0.0:.1f}ms "
        f"freshness_budget_max={entry.get('freshness_budget_ms_max') or 0.0:.1f}ms"
    )
    static_lines.append(f"  reason: {reasons}")
if static_video_entries or static_audio_entries:
    static_lines.append(f"- static video delays: {','.join(static_video_entries)}")
    static_lines.append(f"- static audio delays: {','.join(static_audio_entries)}")
lines.extend(["", *static_lines])
summary_txt.write_text("\n".join(lines) + "\n")
static_txt.write_text("\n".join(static_lines) + "\n")
print("\n".join(lines))
PY
}

if [[ "${LESAVKA_SERVER_RC_MODES}" == "auto" ]]; then
  echo "==> discovering local webcam-backed Lesavka modes"
  LESAVKA_SERVER_RC_MODES="$(discover_local_webcam_modes)"
  LESAVKA_SERVER_RC_MODE_SOURCE=local-v4l2
fi

echo "==> server-to-RC mode matrix"
echo "   ↪ modes=${LESAVKA_SERVER_RC_MODES}"
echo "   ↪ mode_source=${LESAVKA_SERVER_RC_MODE_SOURCE}"
echo "   ↪ profile=${LESAVKA_SERVER_RC_PROFILE} audio_profile=${LESAVKA_SERVER_RC_AUDIO_PROFILE} calibration_profile=${LESAVKA_SERVER_RC_CALIBRATION_PROFILE} capture_seconds=${CAPTURE_SECONDS:-auto} probe_timeout_seconds=${PROBE_TIMEOUT_SECONDS:-auto}"
echo "   ↪ repeat_count=${LESAVKA_SERVER_RC_REPEAT_COUNT} verbose_probes=${LESAVKA_SERVER_RC_VERBOSE_PROBES}"
echo "   ↪ video_delays=${LESAVKA_SERVER_RC_MODE_DELAYS_US}"
echo "   ↪ audio_delays=${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US}"
echo "   ↪ capture_stack=${REMOTE_CAPTURE_STACK} audio_source=${REMOTE_AUDIO_SOURCE} pulse_tool=${REMOTE_PULSE_CAPTURE_TOOL} video_mode=${REMOTE_PULSE_VIDEO_MODE}"
echo "   ↪ tune_delays=${LESAVKA_SERVER_RC_TUNE_DELAYS} confirm=${LESAVKA_SERVER_RC_TUNE_CONFIRM} min_pairs=${LESAVKA_SERVER_RC_TUNE_MIN_PAIRS} max_abs_skew_ms=${LESAVKA_SERVER_RC_TUNE_MAX_ABS_SKEW_MS} max_step_us=${LESAVKA_SERVER_RC_TUNE_MAX_STEP_US} min_change_us=${LESAVKA_SERVER_RC_TUNE_MIN_CHANGE_US}"
echo "   ↪ static_min_runs=${LESAVKA_SERVER_RC_STATIC_MIN_RUNS} static_max_spread_us=${LESAVKA_SERVER_RC_STATIC_MAX_SPREAD_US} static_max_p95_skew_ms=${LESAVKA_SERVER_RC_STATIC_MAX_P95_SKEW_MS} static_max_median_skew_ms=${LESAVKA_SERVER_RC_STATIC_MAX_MEDIAN_SKEW_MS}"
echo "   ↪ freshness_limit_ms=${LESAVKA_SERVER_RC_FRESHNESS_MAX_AGE_MS} min_pairs=${LESAVKA_SERVER_RC_FRESHNESS_MIN_PAIRS}"
echo "   ↪ coded_pairs_min=${LESAVKA_SERVER_RC_MIN_CODED_PAIRS} require_all_coded=${LESAVKA_SERVER_RC_REQUIRE_ALL_CODED_PAIRS} smoothness_gate=${LESAVKA_SERVER_RC_REQUIRE_SMOOTHNESS_PASS}"
echo "   ↪ signal_ready=${LESAVKA_SERVER_RC_SIGNAL_READY} mode=${LESAVKA_SERVER_RC_SIGNAL_READY_MODE} attempts=${LESAVKA_SERVER_RC_SIGNAL_READY_ATTEMPTS} min_pairs=${LESAVKA_SERVER_RC_SIGNAL_READY_MIN_PAIRS} duration=${LESAVKA_SERVER_RC_SIGNAL_READY_DURATION_SECONDS}s warmup=${LESAVKA_SERVER_RC_SIGNAL_READY_WARMUP_SECONDS}s retry_delay=${LESAVKA_SERVER_RC_SIGNAL_READY_RETRY_DELAY_SECONDS}s"
echo "   ↪ signal_conditioning=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_SECONDS}s warmup=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_WARMUP_SECONDS}s gap=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_GAP_SECONDS}s analysis_window=${LESAVKA_SERVER_RC_ANALYSIS_TIMELINE_WINDOW}"
echo "   ↪ reconfigure=${LESAVKA_SERVER_RC_RECONFIGURE} strategy=${LESAVKA_SERVER_RC_RECONFIGURE_STRATEGY} allow_gadget_reset=${LESAVKA_SERVER_RC_ALLOW_GADGET_RESET}"
echo "   ↪ tethys_ready=${LESAVKA_SERVER_RC_WAIT_TETHYS_READY} settle=${LESAVKA_SERVER_RC_TETHYS_SETTLE_SECONDS}s timeout=${LESAVKA_SERVER_RC_TETHYS_READY_TIMEOUT_SECONDS}s preroll_discard=${LESAVKA_SERVER_RC_PREROLL_DISCARD_SECONDS}s"
echo "   ↪ start_delay=${LESAVKA_SERVER_RC_START_DELAY_SECONDS}s"
echo "   ↪ artifact_dir=${MATRIX_REPORT_DIR}"
echo "   ↪ matrix_run_log=${MATRIX_RUN_LOG}"

prime_remote_sudo
sleep_start_delay
prebuild_probe_tools

if ! [[ "${LESAVKA_SERVER_RC_REPEAT_COUNT}" =~ ^[0-9]+$ ]] || (( LESAVKA_SERVER_RC_REPEAT_COUNT < 1 )); then
  printf 'LESAVKA_SERVER_RC_REPEAT_COUNT must be a positive integer; got %s\n' "${LESAVKA_SERVER_RC_REPEAT_COUNT}" >&2
  exit 64
fi

declare -A mode_run_counts=()
matrix_sequence=0
IFS=',' read -r -a modes <<<"${LESAVKA_SERVER_RC_MODES}"
for mode in "${modes[@]}"; do
  mode="${mode//[[:space:]]/}"
  [[ -n "${mode}" ]] || continue
  read -r width height fps < <(parse_mode "${mode}")

  for repeat_index in $(seq 1 "${LESAVKA_SERVER_RC_REPEAT_COUNT}"); do
    mode_run_counts["${mode}"]=$(( ${mode_run_counts["${mode}"]:-0} + 1 ))
    mode_run_index=${mode_run_counts["${mode}"]}
    matrix_sequence=$((matrix_sequence + 1))
    video_delay_us="$(lookup_video_delay_us "${mode}")"
    audio_delay_us="$(lookup_audio_delay_us "${mode}")"
    id_base="$(mode_id "${mode}")"
    run_label="$(printf '%02d' "${mode_run_index}")"
    id="${id_base}__run${run_label}"
    mode_dir="${MATRIX_REPORT_DIR}/${id}"
    mode_log="${mode_dir}/mode-run.log"
    mode_result="${mode_dir}/mode-result.json"
    seed_result="${mode_dir}/mode-result-seed.json"
    readiness_dir="${mode_dir}/signal-readiness"
    readiness_log="${readiness_dir}/signal-readiness-run.log"
    readiness_attempts_json="${readiness_dir}/signal-readiness-attempts.json"
    tuned_log="${mode_dir}/mode-tuned-run.log"
    tuned_result="${mode_dir}/mode-result-tuned.json"
    tune_env="${mode_dir}/mode-tune-candidate.env"
    mkdir -p "${mode_dir}"

    echo "==> mode ${mode} run ${mode_run_index} repeat ${repeat_index}/${LESAVKA_SERVER_RC_REPEAT_COUNT}: video_delay_us=${video_delay_us} audio_delay_us=${audio_delay_us}"
    reconfigure_server_mode "${mode}" "${width}" "${height}" "${fps}" "${audio_delay_us}" "${video_delay_us}"
    wait_tethys_media_ready "${mode}" "${width}" "${height}" "${fps}"

    if [[ "${LESAVKA_SERVER_RC_SIGNAL_READY}" != "0" && "${LESAVKA_SERVER_RC_SIGNAL_READY_MODE}" != "separate" ]]; then
      echo "==> mode ${mode} run ${mode_run_index}: using same-capture signal conditioning before measured probe"
    fi

    if [[ "${LESAVKA_SERVER_RC_SIGNAL_READY}" != "0" && "${LESAVKA_SERVER_RC_SIGNAL_READY_MODE}" == "separate" ]]; then
      mkdir -p "${readiness_dir}"
      echo "==> mode ${mode} run ${mode_run_index}: proving Tethys signal readiness before measured probe"
      readiness_pass=1
      readiness_status=0
      readiness_artifact_dir=""
      readiness_reason="no readiness attempts ran"
      readiness_attempt_jsons=()
      for readiness_attempt in $(seq 1 "${LESAVKA_SERVER_RC_SIGNAL_READY_ATTEMPTS}"); do
        attempt_dir="${readiness_dir}/attempt-${readiness_attempt}"
        readiness_log="${attempt_dir}/signal-readiness-run.log"
        readiness_attempt_json="${attempt_dir}/signal-readiness-attempt.json"
        mkdir -p "${attempt_dir}"
        echo "   ↪ readiness attempt ${readiness_attempt}/${LESAVKA_SERVER_RC_SIGNAL_READY_ATTEMPTS}: requiring ${LESAVKA_SERVER_RC_SIGNAL_READY_MIN_PAIRS} paired coded events"
        run_mode_probe \
          "${width}" \
          "${height}" \
          "${fps}" \
          "${audio_delay_us}" \
          "${video_delay_us}" \
          "${attempt_dir}" \
          "${readiness_log}" \
          "${LESAVKA_SERVER_RC_SIGNAL_READY_DURATION_SECONDS}" \
          "${LESAVKA_SERVER_RC_SIGNAL_READY_WARMUP_SECONDS}" \
          "${LESAVKA_SERVER_RC_SIGNAL_READY_MIN_PAIRS}" \
          0
        readiness_status=${RUN_MODE_PROBE_STATUS}
        readiness_artifact_dir="$(artifact_dir_from_log "${readiness_log}" "${attempt_dir}")"
        set +e
        readiness_reason="$(
          write_signal_readiness_attempt_result \
            "${readiness_attempt}" \
            "${readiness_artifact_dir}" \
            "${readiness_status}" \
            "${readiness_log}" \
            "${LESAVKA_SERVER_RC_SIGNAL_READY_MIN_PAIRS}" \
            "${readiness_attempt_json}" 2>&1
        )"
        readiness_pass=$?
        set -e
        readiness_attempt_jsons+=("${readiness_attempt_json}")
        if [[ "${readiness_pass}" -eq 0 ]]; then
          echo "   ↪ readiness attempt ${readiness_attempt} passed: ${readiness_reason}"
          break
        fi
        [[ -n "${readiness_reason}" ]] || readiness_reason="signal readiness failed"
        echo "   ↪ readiness attempt ${readiness_attempt} failed: ${readiness_reason}"
        if [[ "${readiness_attempt}" -lt "${LESAVKA_SERVER_RC_SIGNAL_READY_ATTEMPTS}" ]]; then
          echo "   ↪ waiting ${LESAVKA_SERVER_RC_SIGNAL_READY_RETRY_DELAY_SECONDS}s before retrying signal readiness"
          sleep "${LESAVKA_SERVER_RC_SIGNAL_READY_RETRY_DELAY_SECONDS}"
        fi
      done
      write_signal_readiness_attempts_summary "${readiness_attempts_json}" "${readiness_attempt_jsons[@]}"
      if [[ "${readiness_pass}" -ne 0 ]]; then
        [[ -n "${readiness_reason}" ]] || readiness_reason="signal readiness failed"
        echo "   ↪ signal readiness failed: ${readiness_reason}"
        write_signal_readiness_failure \
          "${mode}" \
          "${width}" \
          "${height}" \
          "${fps}" \
          "${video_delay_us}" \
          "${audio_delay_us}" \
          "${readiness_status}" \
          "${readiness_log}" \
          "${readiness_artifact_dir}" \
          "${readiness_attempts_json}" \
          "${readiness_reason}" \
          "${mode_result}"
        annotate_mode_result "${mode_result}" "${id_base}" "${mode_run_index}" "${repeat_index}" "${LESAVKA_SERVER_RC_REPEAT_COUNT}" "${matrix_sequence}" "readiness-failure"
        cp "${mode_result}" "${seed_result}"
        if [[ "${LESAVKA_SERVER_RC_CONTINUE_ON_FAIL}" == "0" ]]; then
          break 2
        fi
        continue
      fi
      echo "   ↪ signal readiness passed: artifact_dir=${readiness_artifact_dir}"
    fi

    echo "==> mode ${mode} run ${mode_run_index}: running seed probe"
    run_mode_probe "${width}" "${height}" "${fps}" "${audio_delay_us}" "${video_delay_us}" "${mode_dir}" "${mode_log}"
    run_status=${RUN_MODE_PROBE_STATUS}
    artifact_dir="$(artifact_dir_from_log "${mode_log}" "${mode_dir}")"
    write_mode_result "${mode}" "${width}" "${height}" "${fps}" "${video_delay_us}" "${audio_delay_us}" "${run_status}" "${mode_log}" "${artifact_dir}" "${mode_result}"
    annotate_mode_result "${mode_result}" "${id_base}" "${mode_run_index}" "${repeat_index}" "${LESAVKA_SERVER_RC_REPEAT_COUNT}" "${matrix_sequence}" "seed"
    cp "${mode_result}" "${seed_result}"

    if [[ "${LESAVKA_SERVER_RC_TUNE_DELAYS}" != "0" && "${LESAVKA_SERVER_RC_TUNE_CONFIRM}" != "0" ]]; then
      write_tune_candidate_env "${seed_result}" "${tune_env}"
      # shellcheck disable=SC1090
      source "${tune_env}"
      if [[ "${tune_ready:-false}" == "true" ]]; then
        echo "==> mode ${mode} run ${mode_run_index}: confirming tuned delays video_delay_us=${tune_video_delay_us} audio_delay_us=${tune_audio_delay_us}"
        echo "   ↪ tune delta: video=${tune_video_delta_us}us audio=${tune_audio_delta_us}us pairs=${tune_paired_event_count} drift=${tune_drift_ms}ms"
        run_mode_probe "${width}" "${height}" "${fps}" "${tune_audio_delay_us}" "${tune_video_delay_us}" "${mode_dir}" "${tuned_log}"
        tuned_status=${RUN_MODE_PROBE_STATUS}
        tuned_artifact_dir="$(artifact_dir_from_log "${tuned_log}" "${mode_dir}")"
        write_mode_result "${mode}" "${width}" "${height}" "${fps}" "${tune_video_delay_us}" "${tune_audio_delay_us}" "${tuned_status}" "${tuned_log}" "${tuned_artifact_dir}" "${tuned_result}"
        annotate_mode_result "${tuned_result}" "${id_base}" "${mode_run_index}" "${repeat_index}" "${LESAVKA_SERVER_RC_REPEAT_COUNT}" "${matrix_sequence}" "tuned"
        cp "${tuned_result}" "${mode_result}"
        run_status=${tuned_status}
      else
        echo "   ↪ tune skipped: ${tune_reason:-not ready}"
      fi
    fi

    if [[ "${run_status}" -ne 0 && "${LESAVKA_SERVER_RC_CONTINUE_ON_FAIL}" == "0" ]]; then
      break 2
    fi
  done
done

summarize_matrix

echo "==> done"
echo "artifact_dir: ${MATRIX_REPORT_DIR}"
echo "mode_matrix_summary_json: ${MATRIX_SUMMARY_JSON}"
echo "mode_matrix_summary_csv: ${MATRIX_SUMMARY_CSV}"
echo "mode_matrix_summary_txt: ${MATRIX_SUMMARY_TXT}"
echo "mode_delay_recommendations_json: ${MATRIX_DELAY_JSON}"
echo "mode_delay_recommendations_env: ${MATRIX_DELAY_ENV}"
echo "mode_static_calibration_json: ${MATRIX_STATIC_JSON}"
echo "mode_static_calibration_csv: ${MATRIX_STATIC_CSV}"
echo "mode_static_calibration_txt: ${MATRIX_STATIC_TXT}"
echo "mode_static_calibration_env: ${MATRIX_STATIC_ENV}"
echo "mode_matrix_run_log: ${MATRIX_RUN_LOG}"

if python3 - <<'PY' "${MATRIX_SUMMARY_JSON}"
import json
import pathlib
import sys

summary = json.loads(pathlib.Path(sys.argv[1]).read_text())
raise SystemExit(0 if summary.get("passed") else 1)
PY
then
  exit 0
fi

exit 95
