#!/usr/bin/env bash
# Canonical verification for a completed worktree branch.
# Mirrors CLAUDE.md § Verification. Live-agent marks are excluded (they need a
# real provider session and are not appropriate for an automated landing gate).
#
# `live_daemon` is excluded for a different reason and is worth stating so nobody
# "fixes" it back in: it needs no provider and would run fine here, but it starts
# a daemon and spawns real shells, and landing is meant to be cheap. CI runs it
# on ubuntu-latest and windows-latest on every push, which is where a host-shaped
# regression has to be caught anyway. Run it by hand with
# `uv run pytest tests/test_live_daemon.py -m live_daemon`.
#
# This is safe to run in several worktrees at once. Measured 2026-07-29, three
# concurrent runs took 58/58/62s versus about 60s solo, with 996 passing in each.
# CLAUDE.md records why the suite is parallel-safe.
set -euo pipefail

step() { printf '\n=== %s ===\n' "$*" >&2; }

step "pytest"
# Distributed across the host's physical cores (`-n auto`). The suite is
# function-scoped throughout, keeps its state in per-test tmp dirs, and binds no
# ports, so workers do not interfere; CLAUDE.md § Verification records what was
# measured and why it holds.
#
# `--dist loadgroup` rather than `load` or `worksteal`: it is the only mode that
# honours `xdist_group`, and the real-console files (`test_conpty_integration.py`,
# `test_pty_supervisor.py`) carry that mark so each stays on a single worker
# instead of running its wall-clock-sensitive pseudoconsole tests concurrently
# with itself. Tests without the mark are distributed exactly as in `load`.
#
# `--durations=25` stays on so a test that grows slow is visible in the gate's
# own output rather than only in a run someone thought to ask for.
uv run pytest tests -q -n auto --dist loadgroup --durations=25 -m "not live_agent and not live_subagent and not live_telemetry and not live_quota and not live_automations and not live_mcp and not live_edge_tts and not live_daemon"

step "ruff"
uv run ruff check src/swe_mux tests packaging

step "mypy"
uv run mypy

step "mypy (per-platform implementations)"
# Each host's PTY, process-ownership, and secret-store implementation is
# typechecked under its own platform, on every host. Without this, half the
# platform code is invisible to the type checker on whichever machine happens to
# be running the gate, and only breaks when someone builds on the other one.
uv run mypy --config-file mypy-platform.toml --platform linux \
  src/swe_mux/pty_backend_posix.py \
  src/swe_mux/posix_process_group.py \
  src/swe_mux/posix_guardian.py
uv run mypy --config-file mypy-platform.toml --platform win32 \
  src/swe_mux/pty_backend_windows.py \
  src/swe_mux/win_jobobj.py \
  src/swe_mux/secret_cipher_windows.py

step "frontend tsc"
( cd frontend && npx tsc --noEmit )

step "frontend test tsc"
# The base tsconfig only includes src, so this typechecks everything under test/ - the
# Node unit suites and the Playwright renderer harnesses - against the real components
# and types. It catches a harness prop that has drifted from the component it mounts
# before it can rot into a runtime-only Playwright failure (as pane-layout.spec.ts did),
# and a hand-built unit-test fixture that no longer matches the type it fakes.
( cd frontend && npx tsc --noEmit -p tsconfig.test.json )

step "frontend tests"
( cd frontend && npm test )

printf '\nverification passed\n' >&2
