#!/usr/bin/env bash
# Boundary tripwire: flag domain-taxonomy leaks in the Svelte frontend.
#
# The project rule (CLAUDE.md, docs/architecture/02-svelte-frontend.md) is that
# the frontend is presentation-only and the Rust backend owns domain logic —
# including Jellyfin's item-type *taxonomy* (what the category "Music" means as a
# set of item types). See docs/specs/scoped-search-boundary.md for the incident
# that motivated this check.
#
# ⚠️ This is a TRIPWIRE, NOT A PROOF. A grep cannot distinguish taxonomy-as-policy
# (a leak) from taxonomy-as-display (legitimate: "is this a music card?"). It
# targets the one machine-detectable signature of the leak class — a *query* that
# names a multi-type category — and defers everything subtler to the human
# spec-review checklist (docs/specs/SPEC-REVIEW-CHECKLIST.md). A clean run here
# does not mean the boundary is respected; it means the crudest violation isn't
# present.
#
# What it flags: an `includeItemTypes: [ ... , ... ]` array literal with two or
# more types — i.e. the frontend deciding that a *category* maps to a *set* of
# Jellyfin types, which is domain knowledge the backend should own. Single-type
# query arrays (`includeItemTypes: ["Movie"]`) are a page saying "I show movies"
# and are allowed. Type *inspection* (`item.type === "Audio"`) is display logic
# and is not matched.
#
# Escaping a genuine exception: add the file+reason to the ALLOWLIST below.

set -euo pipefail

cd "$(dirname "$0")/.."

# Files permitted to contain a multi-type includeItemTypes query, with the reason.
# Keep this SHORT. A growing allowlist means the boundary is eroding — that is a
# signal to push taxonomy into Rust, not to keep appending here.
ALLOWLIST=(
  # "Things a person appeared in" is arguably taxonomy, but it is a fixed
  # two-type filmography query with no category-configuration behind it. Tracked
  # as acceptable pending any person-scope work; revisit if it grows.
  "src/lib/components/library/PersonDetailView.svelte"
)

is_allowed() {
  local file="$1"
  for allowed in "${ALLOWLIST[@]}"; do
    [[ "$file" == "$allowed" ]] && return 0
  done
  return 1
}

# Multi-element includeItemTypes array: `includeItemTypes: [ <x> , <y> ... ]`.
# The comma inside the brackets is what makes it multi-type.
PATTERN='includeItemTypes:[[:space:]]*\[[^]]*,[^]]*\]'

echo "🔎 Checking frontend for domain-taxonomy leaks (multi-type query arrays)…"

# Collect hits, excluding tests and the allowlist.
violations=""
while IFS= read -r line; do
  [[ -z "$line" ]] && continue
  file="${line%%:*}"
  case "$file" in
    *.test.*) continue ;;
  esac
  if is_allowed "$file"; then
    echo "  ⏭️  allowlisted: $line"
    continue
  fi
  violations+="$line"$'\n'
done < <(grep -rInE "$PATTERN" src/ 2>/dev/null || true)

if [[ -n "$violations" ]]; then
  echo ""
  echo "❌ Frontend boundary violation: a multi-type includeItemTypes query defines"
  echo "   a category in the presentation layer. That taxonomy belongs in Rust —"
  echo "   send an opaque scope and let the backend expand it to item types."
  echo "   See docs/specs/scoped-search-boundary.md and CLAUDE.md."
  echo ""
  echo "$violations" | sed 's/^/   /'
  echo "   If this is a genuine exception, add the file + reason to ALLOWLIST in"
  echo "   scripts/check-frontend-boundary.sh — but prefer moving it to Rust."
  exit 1
fi

echo "✅ No multi-type taxonomy queries in the frontend."
echo "   (Reminder: this is a tripwire, not a proof — the spec-review checklist is"
echo "    the real gate for subtler leaks.)"
