#!/usr/bin/env bash # verify.sh — the one gate before committing: doc budgets + clean build + tests + scope check. # Usage: ./scripts/verify.sh "path/changed1" "path/changed2" ... # # Why a CLEAN build? An incremental build skips recompiling, so a "0 warnings" report can be a lie # — a nullable warning slipped past exactly that way once. Clean first, then build. # # CONFIGURE the three commands below for the project. Empty means "skip with a warning", so a # docs-only repo works out of the box. set -euo pipefail CLEAN_CMD="" # e.g. 'dotnet clean App.csproj' BUILD_CMD="" # e.g. 'dotnet build App.csproj' TEST_CMD="" # e.g. 'dotnet test Tests/Tests.csproj' WARN_PATTERN=": warning" # what a compiler warning looks like in BUILD_CMD output KNOWN_FLAKY="" # regex of pre-existing flaky test names; anything else fails the gate ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" echo "══ 1/4 DOC BUDGETS ══" # The map stays cheap to read. A commit that PADS a capped file instead of moving detail out # fails here (see AGENTS.md -> Reading budget). check_budget() { local rel="$1" cap="$2" lines [ -f "$ROOT/$rel" ] || { echo " ⚠ $rel not built yet — skipped"; return 0; } 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, decisions.md or git log." return 1 fi printf " ✓ %-12s %3s/%s lines\n" "$rel" "$lines" "$cap" } budget_failed=0 check_budget "AGENTS.md" 210 || budget_failed=1 check_budget "ai.md" 100 || budget_failed=1 check_budget "HANDOFF.md" 40 || budget_failed=1 check_budget "TASKS.md" 120 || budget_failed=1 [ "$budget_failed" -eq 0 ] || exit 1 echo "══ 2/4 CLEAN BUILD (expect 0 warnings) ══" if [ -z "$BUILD_CMD" ]; then echo "⚠ BUILD_CMD not configured — build step skipped." else [ -z "$CLEAN_CMD" ] || eval "$CLEAN_CMD" > /dev/null OUT="$(eval "$BUILD_CMD" 2>&1)" if echo "$OUT" | grep -qI "$WARN_PATTERN"; then echo "✗ WARNINGS FOUND:" echo "$OUT" | grep -i "$WARN_PATTERN" | sort -u exit 1 fi echo "$OUT" | tail -3 echo "✓ Build clean." fi echo "══ 3/4 TEST SUITE ══" if [ -z "$TEST_CMD" ]; then echo "⚠ TEST_CMD not configured — test step skipped." else set +e RUN="$(eval "$TEST_CMD" 2>&1)" EXIT=$? set -e echo "$RUN" | tail -5 if [ "$EXIT" -ne 0 ]; then if [ -n "$KNOWN_FLAKY" ] && ! echo "$RUN" | grep -iE "fail" | grep -qvE "$KNOWN_FLAKY"; then echo "⚠ Failures, but all match the known-flaky whitelist (OK)." else echo "✗ TEST FAILURES — investigate." exit 1 fi fi fi echo "══ 4/4 SCOPE CHECK ══" "$ROOT/scripts/scope-check.sh" "$@" echo "" echo "✓ All gates passed — safe to commit."