#!/usr/bin/env bash
# log-adherence-check.sh existence contract diagnostic.
#
# Reads every sessionKey under the active install's per-account logs and
# asserts that a resolvable claude-agent-stream-<sessionKey>.log exists for
# each. Runs hourly on-device in addition to the in-process timer wired
# from platform/ui/app/lib/claude-agent/logging.ts; both are intentionally
# redundant — one runs inside the server process, this one runs out of band
# so a stalled server still leaves a fresh adherence record.
#
# Emits one `[log-tee] adherence-check window=24h sessions=N misses=M ts=...`
# line to the platform server log on every run. Per-miss lines surface as
# `[log-tee] missing-on-resolve sessionKey=<8> surface=adherence-script
# reason=file-not-on-disk`. `misses=0` is the steady state.
#
# Exit codes:
#   0  No misses (steady state).
#   1  At least one miss recorded.
#   2  Usage / environment error.
set -euo pipefail

# --- Resolve install dir, the same way logs-read.sh does. ---
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLATFORM_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
INSTALL_DIR="$(dirname "$PLATFORM_ROOT")"
INSTALL_DIR_NAME=$(basename "$INSTALL_DIR")
CONFIG_DIR="$HOME/.$INSTALL_DIR_NAME"
SERVER_LOG="$CONFIG_DIR/logs/server.log"

ACCOUNTS_DIR="$INSTALL_DIR/data/accounts"
if [[ ! -d "$ACCOUNTS_DIR" ]]; then
  echo "[log-adherence-check] accounts directory missing: $ACCOUNTS_DIR" >&2
  exit 2
fi

# Window: only count session keys whose stream-log file was modified in the
# last 24h. This avoids fingerprinting long-archived sessions that have aged
# out via the 7-day retention purge.
WINDOW_HOURS=24

# Collect every basename-derived sessionKey from claude-agent-stream-*.log
# files across all account log directories, filtered to the active window.
declare -a KEYS=()
shopt -s nullglob
for log_dir in "$ACCOUNTS_DIR"/*/logs; do
  for f in "$log_dir"/claude-agent-stream-*.log; do
    if [[ -f "$f" ]]; then
      # find -mmin needs minutes; 24h = 1440 min.
      if find "$f" -mmin "-$((WINDOW_HOURS * 60))" -print -quit | grep -q .; then
        base=$(basename "$f")
        key="${base#claude-agent-stream-}"
        key="${key%.log}"
        KEYS+=("$key")
      fi
    fi
  done
done
shopt -u nullglob

# De-duplicate sessionKeys (one session may emit multiple .log files via
# sibling prefixes; the existence contract is per-sessionKey).
declare -A SEEN=()
declare -a UNIQUE=()
for k in "${KEYS[@]:-}"; do
  if [[ -z "${SEEN[$k]:-}" ]]; then
    SEEN[$k]=1
    UNIQUE+=("$k")
  fi
done

SESSIONS=${#UNIQUE[@]}
MISSES=0

# For each sessionKey, verify the agent-stream file is present. Misses
# surface as a missing-on-resolve line. The file we just listed must
# exist by definition; this loop catches the case where a sessionKey was
# referenced in tee/register emissions on server.log but the file itself
# was unlinked between the scan and the check (very rare, but visible).
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
for k in "${UNIQUE[@]:-}"; do
  found=0
  for log_dir in "$ACCOUNTS_DIR"/*/logs; do
    if [[ -f "$log_dir/claude-agent-stream-${k}.log" ]]; then
      found=1
      break
    fi
  done
  if [[ $found -eq 0 ]]; then
    MISSES=$((MISSES + 1))
    echo "${TS} [log-tee] missing-on-resolve sessionKey=${k:0:8} surface=adherence-script reason=file-not-on-disk" >> "$SERVER_LOG" 2>/dev/null || true
  fi
done

# duplicate-basename check. Two stream-log files for one
# sessionKey across account dirs is the structural-failure signature this
# task exists to make impossible. The build gate prevents the writer-side
# regression that produces it (sessions.ts:568 wrong-identifier path); this
# diagnostic is the runtime backstop on every device, every hour. `dup=0`
# is the steady state; `dup>0` is a P0 page (the writer collapse regressed).
declare -A BASENAME_COUNT=()
for log_dir in "$ACCOUNTS_DIR"/*/logs; do
  for f in "$log_dir"/claude-agent-stream-*.log; do
    if [[ -f "$f" ]]; then
      base=$(basename "$f")
      key="${base#claude-agent-stream-}"
      key="${key%.log}"
      BASENAME_COUNT[$key]=$(( ${BASENAME_COUNT[$key]:-0} + 1 ))
    fi
  done
done
DUP_BASENAMES=0
for k in "${!BASENAME_COUNT[@]}"; do
  if [[ ${BASENAME_COUNT[$k]} -gt 1 ]]; then
    DUP_BASENAMES=$((DUP_BASENAMES + 1))
    echo "${TS} [log-tee] dup-basename sessionKey=${k:0:8} count=${BASENAME_COUNT[$k]} surface=adherence-script P0: writer collapse regressed" >> "$SERVER_LOG" 2>/dev/null || true
  fi
done

echo "${TS} [log-tee] adherence-check window=${WINDOW_HOURS}h sessions=${SESSIONS} misses=${MISSES} dup-basenames=${DUP_BASENAMES} surface=script ts=${TS}" >> "$SERVER_LOG" 2>/dev/null || true
echo "[log-adherence-check] sessions=${SESSIONS} misses=${MISSES} dup-basenames=${DUP_BASENAMES} window=${WINDOW_HOURS}h"

if [[ $MISSES -gt 0 || $DUP_BASENAMES -gt 0 ]]; then
  exit 1
fi
exit 0
