#!/usr/bin/env bash # verify.sh — One gate before committing: clean build (0 warnings) + full test run + scope check. # Usage: ./scripts/verify.sh "file1.cs" "file2.cs" ... # # Why a clean build? An incremental build SKIPS recompiling unchanged projects, so a # "0 Warning(s)" from an incremental build can be a lie (CS8601 slipped past this way on # 2026-08-29). This script forces a full rebuild so the 0-warning claim is only ever made # against fresh compiler output. # # Requires WINDOWS dotnet (never Linux dotnet — it re-downloads the windowsdesktop packs # over the slow 9p bridge; see docs/ai/environment.md -> Run). Reads the Windows path from the # WSL mount. set -euo pipefail DOTNET="/mnt/c/Program Files/dotnet/dotnet.exe" [ -x "$DOTNET" ] || { echo "❌ Windows dotnet not found at $DOTNET"; exit 1; } ROOT="$(cd "$(dirname "$0")/.." && pwd)" ROOTWIN="$(wslpath -w "$ROOT")" echo "══ 1/4 DOC BUDGETS ══" # The map stays cheap to read. A commit that PADS a capped file instead of replacing or # moving detail fails here (see AGENTS.md -> Reading budget). check_budget() { local rel="$1" cap="$2" lines [ -f "$ROOT/$rel" ] || { echo "✗ $rel is missing"; exit 1; } lines=$(wc -l < "$ROOT/$rel") if [ "$lines" -gt "$cap" ]; then echo "✗ $rel is $lines lines (cap $cap)." echo " Move the detail to docs/ai/.md, MyMistakes.md or git log — do not pad." exit 1 fi printf " ✓ %-12s %3s/%s lines\n" "$rel" "$lines" "$cap" } check_budget "AGENTS.md" 210 check_budget "ai.md" 100 check_budget "HANDOFF.md" 40 check_budget "TASKS.md" 120 echo "══ 2/4 CLEAN BUILD (expect 0 warnings) ══" "$DOTNET" clean "$ROOTWIN\\ytLive.csproj" > /dev/null OUT="$("$DOTNET" build "$ROOTWIN\\ytLive.csproj" 2>&1)" if echo "$OUT" | grep -qI ": warning"; then echo "✗ WARNINGS FOUND:" echo "$OUT" | grep -iE ": warning" | sort -u exit 1 fi echo "$OUT" | grep -E "Build succeeded" || { echo "$OUT" | tail -5; exit 1; } echo "✓ Build clean, 0 warnings." echo "══ 3/4 TEST SUITE ══" TESTDLL="$ROOTWIN\\ytLive.Tests\\bin\\Debug\\net8.0-windows10.0.19041.0\\ytLive.Tests.dll" "$DOTNET" build "$ROOTWIN\\ytLive.Tests\\ytLive.Tests.csproj" > /dev/null set +e TEST_ARGS=("$TESTDLL") if [ "${PHYSICAL_TESTS:-0}" != "1" ]; then TEST_ARGS+=("--TestCaseFilter:FullyQualifiedName!~RealMouseDrag") fi RUN_RAW="$("$DOTNET" vstest "${TEST_ARGS[@]}" 2>&1)" TEST_EXIT=$? set -e echo "$RUN_RAW" | grep -iE "Passed!|Failed!" | tail -1 # Known pre-existing failures (see HANDOFF.md: do not chase). Anything beyond # these is a real regression and fails the gate. FAILS="$(echo "$RUN_RAW" | grep -iE "\[FAIL\]" || true)" KNOWN=$(echo "$FAILS" | grep -cE "Mix_HonorsProviderGains_AndGameMute_KillsTheLoopback|Round_Clip_Corner_Is_Grabbable_And_Shape_Is_Circle|RealMouseDrag_OnTheLayerList_PersistsTheReorder" || true) echo "$FAILS" | sort -u || true if [ "$TEST_EXIT" -ne 0 ] && [ "$KNOWN" -eq 0 ]; then echo "✗ TEST FAILURES that are NOT the known pre-existing pair — investigate." exit 1 fi if [ "$TEST_EXIT" -ne 0 ]; then echo "⚠ Test exit=$TEST_EXIT but only the 2 known pre-existing failures present (OK)." fi echo "══ 4/4 SCOPE CHECK ══" "$ROOT/scripts/scope-check.sh" "$@" echo "" echo "✓ All gates passed — safe to commit."