#!/usr/bin/env bash
# Verify fixture-timing/jun11-good on this Pi matches expected release markers.
#
# Usage:
#   cd ~/EtherGold/4-Board\ Test\ Fixture/sync
#   bash verify_fixture_software.sh
#
# Exit 0 = all checks pass. Exit 1 = stale or incomplete tree (re-copy or pull).

if grep -q $'\r' "${BASH_SOURCE[0]}" 2>/dev/null; then
  sed -i 's/\r$//' "${BASH_SOURCE[0]}"
  exec bash "${BASH_SOURCE[0]}" "$@"
fi

set -euo pipefail

SYNC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=ethergold_paths.sh
source "${SYNC}/ethergold_paths.sh"

if [[ -d "${ETHERGOLD_BRIDGE}/jun11-good" ]]; then
  FIXTURE="${ETHERGOLD_ROOT}"
  TIMING="${ETHERGOLD_BRIDGE}"
  GOOD="${ETHERGOLD_BRIDGE}/jun11-good"
  PROD_DIR="${ETHERGOLD_DAEMON}"
  RUN_BRIDGE_PROD="${ETHERGOLD_BRIDGE}/run_bridge_prod.sh"
elif [[ -d "${ETHERGOLD_LEGACY_TIMING}/jun11-good" ]]; then
  FIXTURE="${ETHERGOLD_LEGACY_FIXTURE}"
  TIMING="${ETHERGOLD_LEGACY_TIMING}"
  GOOD="${TIMING}/jun11-good"
  PROD_DIR="${TIMING}/jun11-prod"
  RUN_BRIDGE_PROD="${PROD_DIR}/run_bridge_prod.sh"
else
  FIXTURE="$(cd "${SYNC}/.." && pwd)"
  TIMING="${FIXTURE}/fixture-timing"
  GOOD="${TIMING}/jun11-good"
  PROD_DIR="${TIMING}/jun11-prod"
  RUN_BRIDGE_PROD="${PROD_DIR}/run_bridge_prod.sh"
fi

# Milestone baseline (2026-06-24 listen + bridge PASS): v16n pyserial, not uartd default.
EXPECTED_PARSER_BUILD="jun11-good-gpio7-wire-len-parser-v16ac-progressive-0a-csv"
EXPECTED_PARSER_BUILD_PROD="jun11-prod-v16ac-progressive-0a-csv"

fail=0
ok() { echo "  OK   $*"; }
bad() { echo "  FAIL $*"; fail=$((fail + 1)); }

echo "=== verify_fixture_software ==="
echo "Hostname: $(hostname -s 2>/dev/null || hostname)"
echo "Fixture:  ${FIXTURE}"
echo "Bridge:   ${TIMING}"
echo "Daemon:   ${PROD_DIR}"
echo ""

if [[ ! -d "${GOOD}" ]]; then
  bad "missing ${GOOD} — thumb drive must include fixture-timing/jun11-good (sync/ alone is not enough)"
  exit 1
fi

CORE="${GOOD}/pog422_fixture_core.py"
BRIDGE="${GOOD}/pog422_fixture_bridge.py"
RUN="${TIMING}/run_bridge_jun11_good.sh"
RUN_LISTEN="${TIMING}/run_listen_jun11_good.sh"
MIGRATE="${SYNC}/migrate_dropbox_paths.sh"
PATHS="${SYNC}/dropbox_paths.sh"

if [[ ! -f "${CORE}" ]]; then bad "missing ${CORE}"; else
  if grep -q "FIXTURE_PARSER_BUILD = \"${EXPECTED_PARSER_BUILD}\"" "${CORE}"; then
    ok "parser_build ${EXPECTED_PARSER_BUILD}"
  else
    got="$(grep -m1 '^FIXTURE_PARSER_BUILD' "${CORE}" 2>/dev/null || echo '(not found)')"
    bad "parser_build — expected ${EXPECTED_PARSER_BUILD}; have: ${got}"
  fi
fi

if [[ ! -f "${BRIDGE}" ]]; then bad "missing ${BRIDGE}"; else
  if grep -q 'status_0d_block_all' "${BRIDGE}"; then
    ok "bridge status_0d_block_all present"
  else
    bad "bridge missing status_0d_block_all (pre-v8 software)"
  fi
  if grep -q 'status_0d_synth' "${BRIDGE}"; then
    ok "bridge status_0d_synth present"
  else
    bad "bridge missing status_0d_synth (pre-v9 software)"
  fi
  if grep -q 'build_status_0d_from_template' "${BRIDGE}"; then
    ok "bridge status_0d synth-built present"
  else
    bad "bridge missing build_status_0d_from_template (pre-v12 software)"
  fi
  if grep -q 'reason="await_passthrough"' "${BRIDGE}"; then
    ok "bridge round-synth defers to first passthrough"
  else
    bad "bridge missing await_passthrough defer (pre-v14b software)"
  fi
  if grep -q 'Every ETH frame injects to the local T340+ POG422' "${BRIDGE}" \
    && grep -q '_remember_gameplay_round_eth_inject' "${BRIDGE}" \
    && grep -q '_local_slave_tid' "${BRIDGE}" \
    && grep -q '_pending.append' "${BRIDGE}" \
    && grep -q 'status_0d_block_all and meta.msg_type == 0x0D' "${BRIDGE}"; then
    ok "bridge eth inject all; local-tid x9 inject-store; 0x0D block-only"
  else
    bad "bridge missing v16e inject-all / local-tid x9 inject-store invariant"
  fi
  if grep -q '_note_local_slave_tid_from_uart_origin' "${BRIDGE}" \
    && grep -q 'local_slave_tid_learned' "${BRIDGE}" \
    && grep -q '_meta_is_local_for_round_state' "${BRIDGE}"; then
    ok "bridge local TID learned from UART origin only (v16e)"
  else
    bad "bridge missing v16e uart-origin local TID learning"
  fi
  if grep -q 'local_x1_glued' "${CORE}" \
    && grep -q 'status_synth_x1_trigger_ok' "${CORE}" \
    && grep -q 'self._local_slave_tid' "${BRIDGE}"; then
    ok "core v16f local x1 synth when glued with trailing bus packets"
  else
    bad "core missing v16f local_x1_glued synth trigger"
  fi
  if grep -q 'local_slave_tid_uart_learn_ok' "${CORE}" \
    && grep -q 'BANK_PROGRESSIVE_BROADCAST_TID' "${CORE}" \
    && grep -q 'local_slave_tid_uart_learn_ok' "${BRIDGE}"; then
    ok "core v16g ignores bank 0x0A tid=0000 for local TID learn"
  else
    bad "core missing v16g bank-progressive TID filter"
  fi
  if grep -q 'def wire_len_valid' "${CORE}" \
    && grep -q 'wire_len_crop' "${CORE}" \
    && grep -q 'never hunt interior EOP' "${CORE}"; then
    ok "core v16h suppresses EOP-hunt wire-len crops"
  else
    bad "core missing v16h EOP-hunt crop suppress"
  fi
  if grep -q 'uart_echo_false_glued_wager' "${CORE}" \
    && grep -q 'strict_slv_idle' "${BRIDGE}" \
    && grep -q 'x9_inject_dedupe' "${BRIDGE}" \
    && grep -q 'x9_eth_inject_dedupe' "${BRIDGE}" \
    && grep -q 'uart_x9_echo_status' "${BRIDGE}"; then
    ok "core v16k x9 delivery guard (eth inject dedupe, echo status skip)"
  else
    bad "core missing v16k x9 eth inject dedupe"
  fi
  if grep -q 'handshake_post_x9_inject_handoff' "${CORE}" \
    && grep -q 'POST_X9_INJECT_FIFO_GRACE_MS' "${CORE}" \
    && grep -q 'post_x9_inject_echo_drain' "${CORE}" \
    && grep -q 'post_x9_inject_handoff' "${BRIDGE}"; then
    ok "core v16m post-x9 handoff drain+burst (uartd cap_end_inject_window)"
  else
    bad "core missing v16m post-x9 handoff drain+burst"
  fi
  if grep -q 'eth_inject_tid_blacklist_add' "${CORE}" \
    && grep -q '_eth_inject_tid_blacklist' "${BRIDGE}" \
    && grep -q '_blacklist_eth_inject_tid' "${BRIDGE}" \
    && grep -q 'local_slave_tid_learn_skip' "${BRIDGE}" \
    && grep -q 'ETH_INJECT_TID_BLACKLIST_MAX' "${CORE}"; then
    ok "core v16n eth-inject TID blacklist blocks local TID learn from echo"
  else
    bad "core missing v16n eth-inject TID blacklist"
  fi
  if grep -q 'hs_inactive_perf_ns: Optional\[int\] = None' "${CORE}"; then
    ok "core v16p finalize_handshake_window accepts hs_inactive_perf_ns"
  else
    bad "core missing v16p uartd window kwarg fix"
  fi
  if grep -q 'def ois_raw_forward_ok' "${CORE}" \
    && grep -q 'def channel_uses_raw_hs_window' "${CORE}" \
    && grep -q 'forward_uart_raw_window_to_eth_directional' "${BRIDGE}" \
    && grep -q 'queue_eth_raw' "${BRIDGE}" \
    && grep -q 'bridge_forward' "${BRIDGE}" \
    && grep -q 'apply_ois_bridge_defaults' "${BRIDGE}"; then
    ok "core/bridge v16p OIS raw HS opaque forward (no gameplay parse)"
  else
    bad "core/bridge missing v16p OIS raw forward path"
  fi
  if grep -q 'def fixture_eth_tag_payload' "${CORE}" \
    && grep -q 'def resolve_bridge_channels' "${CORE}" \
    && grep -q 'note_uart_origin_after_eth_tx' "${BRIDGE}" \
    && grep -q 'run_bridge_directional_dual' "${BRIDGE}" \
    && grep -q 'eth_to_uart_thread_directional_dual' "${BRIDGE}" \
    && grep -q 'dual_uart_to_eth_thread' "${BRIDGE}" \
    && grep -q 'relay_x1_inject' "${BRIDGE}" \
    && grep -q 'native_uart_status_close' "${BRIDGE}" \
    && grep -q 'CHANNEL=both requires POG422_UARTD=0' "${GOOD}/hat_fixture_bridge.sh"; then
    ok "core/bridge v16s UART-learn TID + relay status synth (no topology map)"
  else
    bad "core/bridge missing v16s UART-learn / relay synth path"
  fi
  if grep -q 'local_origin_x9' "${CORE}" \
    && grep -q 'post_x9_inject_grace_arm' "${CORE}" \
    && grep -q 'synth_defer' "${BRIDGE}"; then
    ok "core/bridge v16u local x9 grace + defer synth (no _tx_lock deadlock)"
  else
    bad "core/bridge missing v16u local x9 grace / defer synth"
  fi
  if grep -q 'is_gameplay_ack(chunk\[1\])' "${CORE}"; then
    ok "core v16v post-x9 grace absorbs all gameplay x1 acks (not 0x71-only)"
  else
    bad "core missing v16v is_gameplay_ack grace absorb"
  fi
  if grep -q 'POST_X9_INJECT_LOCAL_TID_FIFO_GRACE_MS = 25.0' "${CORE}"; then
    ok "core v16w local-TID post-x9 grace 25 ms (relay/default 15 ms)"
  else
    bad "core missing v16w POST_X9_INJECT_LOCAL_TID_FIFO_GRACE_MS=25"
  fi
  if grep -q '_grace_gate_machine' "${BRIDGE}" \
    && grep -q 'post_x9_grace_ois' "${BRIDGE}" \
    && grep -q 'post_x9_grace_active' "${CORE}"; then
    ok "bridge v16x defer OIS inject during machine local post-x9 grace"
  else
    bad "bridge missing v16x OIS defer during post-x9 grace"
  fi
  if grep -q 'post_x9_local_grace_active' "${CORE}" \
    && grep -q 'post_x9_grace_machine_relay' "${BRIDGE}" \
    && grep -q 'filter_handoff_capture_to_x1_only' "${CORE}" \
    && grep -q 'post_x9_handoff_capture_reject' "${CORE}" \
    && grep -q 'status_0d_x9_inject_store_skip' "${BRIDGE}" \
    && grep -q 'local_wager_in_flight' "${BRIDGE}"; then
    ok "v16y machine relay defer + handoff x1 guard + local wager relay dedupe skip"
  else
    bad "core/bridge missing v16y grace relay defer / handoff guard / relay store skip"
  fi
  if grep -q 'is_progressive_broadcast' "${CORE}" \
    && grep -q 'TrunkRoundState' "${BRIDGE}" \
    && grep -q 'transaction_defer' "${BRIDGE}" \
    && grep -q '0a_latest_wins' "${BRIDGE}" \
    && grep -q 'game_transaction_gate' "${BRIDGE}" \
    && grep -q '_deferred_0a_latest' "${BRIDGE}"; then
    ok "v16z game transaction gate + progressive 0A latest-wins defer"
  else
    bad "core/bridge missing v16z transaction gate / 0A latest-wins defer"
  fi
  if grep -q 'local_tid_always_pass_transaction_gate' "${BRIDGE}" \
    && grep -q '_meta_is_local_terminal(meta)' "${BRIDGE}"; then
    ok "v16ab local-TID always pass transaction gate (Master retry inject)"
  else
    bad "bridge missing v16ab local-TID always pass transaction gate"
  fi
  if grep -q 'decode_progressive_0a' "${CORE}" \
    && grep -q 'ProgressiveCsvWriter' "${CORE}" \
    && grep -q '_try_progressive_csv_update' "${BRIDGE}"; then
    ok "v16ac Master 0x0A → progressives.csv hook"
  else
    bad "core/bridge missing v16ac progressive 0A CSV writer"
  fi
  if grep -q 'local_tid_x9_never_eth_inject_dedupe' "${BRIDGE}" \
    && grep -q '_meta_is_local_terminal(meta)' "${BRIDGE}"; then
    ok "v16aa local-TID x9 never eth inject dedupe (Master retry pass-through)"
  else
    bad "bridge missing v16aa local-TID x9 never dedupe Master retries"
  fi
  if grep -q 'jun11-prod-v16ac-progressive-0a-csv' "${CORE}"; then
    ok "core prod build string ${EXPECTED_PARSER_BUILD_PROD}"
  else
    got="$(grep -m1 '^FIXTURE_PARSER_BUILD_PROD' "${CORE}" 2>/dev/null || echo '(not found)')"
    bad "prod build — expected ${EXPECTED_PARSER_BUILD_PROD}; have: ${got}"
  fi
  if [[ -f "${GOOD}/pog422_uart_client.py" ]] \
    && [[ -f "${GOOD}/pog422_uart_capture.py" ]] \
    && grep -q 'UartCaptureHandler' "${BRIDGE}" \
    && grep -q 'POG422_UARTD' "${GOOD}/hat_fixture_bridge.sh" \
    && grep -q 'pog422_start_uartd' "${GOOD}/hat_fixture_bridge.sh" \
    && grep -q 'suspend_uart' "${GOOD}/pog422_uart_client.py" \
    && grep -q 'use_uartd_inject' "${BRIDGE}" \
    && grep -q '_acquire_python_serial' "${BRIDGE}" \
    && grep -q 'POG422_UARTD_INJECT' "${GOOD}/hat_fixture_bridge.sh" \
    && grep -q 'POG422_IPC_UART_SUSPEND' "${TIMING}/inject-shim/pog422_ipc.h" 2>/dev/null; then
    ok "optional uartd A/B code present (milestone uses POG422_UARTD=0 via run_bridge_jun11_good.sh)"
  else
    bad "bridge missing optional uartd path (files for future A/B vs pyserial)"
  fi
  if grep -q 'outcome\[STATUS_0D_X9_COUNTER_BYTE\] != 0' "${CORE}"; then
    bad "core still rejects x9 byte17==0 (pre-v15c zero-wrap bug)"
  else
    ok "core v15c accepts x9 byte17 zero wrap"
  fi
  PROD_SUP="${PROD_DIR}/fixture_supervisor.py"
  if [[ -f "${PROD_SUP}" ]]; then
    ok "jun11-prod supervisor present"
  else
    bad "missing jun11-prod production stack"
  fi
  if [[ -f "${RUN_BRIDGE_PROD}" ]] \
    && grep -q 'STATS_INTERVAL=0' "${RUN_BRIDGE_PROD}" \
    && grep -q 'FIXTURE_PROD=1' "${RUN_BRIDGE_PROD}"; then
    ok "jun11-prod run_bridge_prod errors-only config"
  else
    bad "jun11-prod run_bridge_prod missing prod hardening"
  fi
  if [[ -f "${PROD_DIR}/prod_log_manager.py" ]]; then
    ok "jun11-prod prod_log_manager (10 KiB rotate, 24 h prune)"
  else
    bad "missing jun11-prod/prod_log_manager.py"
  fi
  if [[ -f "${RUN_BRIDGE_PROD}" ]] \
    && grep -q 'FIXTURE_PROD_ERRORS_MAX_BYTES:-10240' "${RUN_BRIDGE_PROD}"; then
    ok "jun11-prod default 10 KiB errors.jsonl rotation"
  else
    bad "jun11-prod run_bridge_prod missing 10 KiB default rotation"
  fi
  if grep -q 'PROD_SYNTH_SKIP_LOG_REASONS' "${CORE}" \
    && grep -q 'rotate_file_if_large' "${CORE}" \
    && grep -q "${EXPECTED_PARSER_BUILD_PROD}" "${CORE}"; then
    ok "core v4 field resilience prod + errors.jsonl rotation"
  else
    bad "core missing v4 field resilience prod logging"
  fi
  if [[ -f "${SYNC}/ethergold_paths.sh" ]] && [[ -f "${SYNC}/migrate_field_layout.sh" ]]; then
    ok "sync/ethergold_paths.sh + migrate_field_layout.sh present"
  else
    bad "missing sync/ethergold_paths.sh or migrate_field_layout.sh"
  fi
  if [[ -d "${ETHERGOLD_LOGS:-${TIMING}/logs}" ]]; then
    ok "logs directory present"
  else
    bad "missing logs directory (${ETHERGOLD_LOGS:-${TIMING}/logs})"
  fi
  COMMISSION="${PROD_DIR}/commission_prod_boot.sh"
  if [[ -f "${COMMISSION}" ]] && [[ "$(wc -c < "${COMMISSION}" | tr -d ' ')" -gt 100 ]]; then
    ok "jun11-prod commission_prod_boot.sh present"
  else
    bad "jun11-prod commission_prod_boot.sh missing or empty (re-deploy from PC)"
  fi
  if grep -q 'supervisor_eth_replug' "${PROD_SUP}" \
    && grep -q 'supervisor_eth_port_change' "${PROD_SUP}" \
    && grep -q 'read_eth_carriers' "${PROD_SUP}"; then
    ok "jun11-prod supervisor eth carrier state machine"
  else
    bad "jun11-prod supervisor missing eth carrier state machine"
  fi
  if grep -q 'eth_relay_live_ports_only' "${CORE}" \
    && grep -q 'live_ports_only=router.eth_relay_live_ports_only' "${BRIDGE}"; then
    ok "bridge eth relay live_ports_only wired"
  else
    bad "bridge missing eth relay live_ports_only"
  fi
  if grep -q 'reopen_port' "${CORE}"; then
    ok "core DirectionalEthRouter.reopen_port present"
  else
    bad "core missing DirectionalEthRouter.reopen_port"
  fi
  if [[ -f "${SYNC}/switch_prod_bridge.sh" ]]; then
    ok "sync/switch_prod_bridge.sh present"
  else
    bad "missing sync/switch_prod_bridge.sh"
  fi
  if grep -q 'build_status_0d_from_round' "${CORE}"; then
    ok "core build_status_0d_from_round present"
  else
    bad "core missing build_status_0d_from_round (pre-v14 software)"
  fi
  if grep -q 'status_0d_first_passthrough' "${BRIDGE}"; then
    ok "bridge status_0d_first_passthrough present"
  else
    bad "bridge missing status_0d_first_passthrough (pre-v13 software)"
  fi
  if grep -q 'status_0d_first_only' "${BRIDGE}" && grep -q 'status_0d_dedupe' "${BRIDGE}"; then
    ok "bridge status_0d_first_only dedupe present"
  else
    bad "bridge missing status_0d_first_only (pre-v7 software)"
  fi
fi

if [[ -f "${RUN}" ]]; then
  if grep -q 'FIXTURE_STATUS_0D_FIRST_ONLY' "${RUN}"; then
    ok "run_bridge_jun11_good.sh exports FIXTURE_STATUS_0D_FIRST_ONLY"
  else
    bad "run_bridge_jun11_good.sh missing FIXTURE_STATUS_0D_FIRST_ONLY"
  fi
  if grep -q 'FIXTURE_STATUS_0D_FIRST_PASSTHROUGH="${FIXTURE_STATUS_0D_FIRST_PASSTHROUGH:-1}"' "${RUN}"; then
    ok "run_bridge_jun11_good.sh default FIRST_PASSTHROUGH=1"
  else
    bad "run_bridge_jun11_good.sh FIRST_PASSTHROUGH default not 1"
  fi
  if grep -q 'POG422_UARTD="${POG422_UARTD:-0}"' "${RUN}" \
    && grep -q 'POG422_UARTD_INJECT="${POG422_UARTD_INJECT:-0}"' "${RUN}"; then
    ok "run_bridge_jun11_good.sh milestone defaults POG422_UARTD=0 pyserial inject"
  else
    bad "run_bridge_jun11_good.sh must default POG422_UARTD=0 (v16n milestone pyserial)"
  fi
else
  bad "missing ${RUN}"
fi

if [[ -f "${RUN_LISTEN}" ]]; then
  if grep -q 'jun11-good' "${RUN_LISTEN}" \
    && grep -q 'pog422_uartd is running' "${RUN_LISTEN}"; then
    ok "run_listen_jun11_good.sh pyserial listen (warns if uartd running)"
  else
    bad "run_listen_jun11_good.sh missing jun11-good pyserial listen wiring"
  fi
else
  bad "missing ${RUN_LISTEN}"
fi

if [[ -f "${PATHS}" ]]; then ok "sync/dropbox_paths.sh present"; else bad "missing ${PATHS}"; fi
if [[ -f "${MIGRATE}" ]]; then ok "sync/migrate_dropbox_paths.sh present"; else bad "missing ${MIGRATE}"; fi
if [[ -f "${SYNC}/upload_capture.rclone-filter" ]] \
  && grep -q 'filter-from.*upload_capture.rclone-filter' "${SYNC}/sync_to_dropbox.sh"; then
  ok "sync_to_dropbox.sh uses upload_capture.rclone-filter (--filter-from)"
else
  bad "sync_to_dropbox.sh missing rclone --filter-from upload_capture.rclone-filter"
fi

if [[ -f "${SYNC}/rclone.env" ]]; then
  if grep -q 'Cursor OHD Project' "${SYNC}/rclone.env"; then
    ok "rclone.env → OHD workspace path"
    grep -E '^DROPBOX_(DEST|FIXTURE_ROOT)=' "${SYNC}/rclone.env" | sed 's/^/        /'
  elif grep -q 'Hardware Development' "${SYNC}/rclone.env"; then
    bad "rclone.env still on legacy Hardware Development path — run: bash migrate_dropbox_paths.sh"
  else
    bad "rclone.env DROPBOX paths unrecognized"
  fi
else
  bad "missing ${SYNC}/rclone.env — run bash install.sh"
fi

if [[ -f "${CORE}" ]]; then
  if python3 -c "import sys; sys.path.insert(0, '${GOOD}'); from pog422_fixture_core import verify_pog422_checksum_selftest; verify_pog422_checksum_selftest()"; then
    ok "pog422 checksum selftest"
  else
    bad "pog422 checksum selftest failed"
  fi
fi

for _forbidden in \
  "${TIMING}/Legacy Code" \
  "${TIMING}/Legacy" \
  "${TIMING}/v18r Code"; do
  if [[ -d "${_forbidden}" ]]; then
    bad "POG source must not be on Pi: ${_forbidden} — rm -rf and update pull filter"
    fail=1
  fi
done
if [[ ! -d "${TIMING}/Legacy Code" && ! -d "${TIMING}/Legacy" && ! -d "${TIMING}/v18r Code" ]]; then
  ok "no POG firmware source trees under fixture-timing"
fi

if [[ -f "${SYNC}/fixture_timing.rclone-filter" ]] \
  && grep -q 'Legacy Code' "${SYNC}/fixture_timing.rclone-filter"; then
  ok "pull filter excludes fixture-timing/Legacy Code"
else
  bad "fixture_timing.rclone-filter must exclude POG Legacy Code from Pi pull"
fi

if [[ -x "${SYNC}/stop_fixture_gremlins.sh" ]]; then
  ok "stop_fixture_gremlins.sh present in sync/"
else
  bad "missing ${SYNC}/stop_fixture_gremlins.sh — run pull_fixture_shared_from_dropbox.sh"
fi

_RUN_BRIDGE="${TIMING}/run_bridge_jun11_good.sh"
if [[ ! -f "${_RUN_BRIDGE}" ]]; then
  _RUN_BRIDGE="${FIELD_BRIDGE}/run_bridge_jun11_good.sh"
fi
if [[ -f "${_RUN_BRIDGE}" ]] && grep -q 'stop_fixture_gremlins' "${_RUN_BRIDGE}"; then
  ok "run_bridge_jun11_good.sh auto-runs stop_fixture_gremlins"
else
  bad "run_bridge_jun11_good.sh must call stop_fixture_gremlins before bridge start"
fi
unset _RUN_BRIDGE

echo ""
if [[ "${fail}" -eq 0 ]]; then
  echo "All checks passed. Milestone stack: v16ac progressive CSV + v16ab local TID always pass gate + v16aa local x9 never dedupe + v16z transaction gate + v16y grace relay defer + v16x OIS defer + dual bridge (POG422_UARTD=0)."
  echo "  Bridge: cd ${TIMING} && FIXTURE_POS=N CHANNEL=both ./run_bridge_jun11_good.sh"
  echo "  Single: CHANNEL=machine|ois FIXTURE_POS=N ./run_bridge_jun11_good.sh"
  echo "  Listen: cd ${TIMING} && FIXTURE_POS=N ./run_listen_jun11_good.sh"
  echo "Confirm session_start: parser_build=${EXPECTED_PARSER_BUILD}"
  echo "  inject_engine=python, uartd=false, status_0d_synth=true"
  exit 0
fi

echo "${fail} check(s) failed."
echo ""
echo "Fix options:"
echo "  1. Thumb drive: copy PC folder fixture-timing/ (entire tree) to ${TIMING}/"
echo "  2. After PC Dropbox sync: cd ${SYNC} && bash pull_all_from_dropbox.sh"
echo "  3. Then: bash pi_normalize.sh && bash install_sync.sh"
exit 1
