One file (AGENTS.md) that bootstraps the rest: rules, the file map to create, what belongs in each file, the first-session interview order, and the list of anti-patterns that killed the previous map (1,308-line guide, 63 task files, narrative history inline, sessions skimming 56k tokens of context). Separates four kinds of content by read frequency: rules/invariants -> AGENTS.md (every session) subsystem truth -> docs/ai/<topic>.md (only the matching one) lookups -> environment.md (grepped, never read) retired decisions -> decisions.md (only when re-opening one) Caps are enforced, not promised: scripts/verify.sh checks doc budgets before the build, so a commit that pads a capped file fails. Proven both ways — it passes clean and exits 1 on an over-cap file. scripts/scope-check.sh blocks edits outside the declared file list. templates/ holds fill-in skeletons for the seven files a project must create. CC0: copy it, rename it, sell it, no attribution needed.
82 lines
2.9 KiB
Bash
82 lines
2.9 KiB
Bash
#!/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/<topic>.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."
|