#!/usr/bin/env bash # check.sh — the ROUND's verify (decision 1822): fmt everywhere (cheap), clippy + test scoped to # the crates this round's changes can actually affect — the changed crates plus everything that # depends on them. The workspace-wide chain is `scripts/gates.sh`'s job, paid at sync→land. # # Why this verb exists: the fleet was paying the FULL chain per round — measured over the fortnight # to 2026-09-01 at 3,028 `cargo test --workspace` runs (72 h of wall time) and 1,572 workspace-wide # clippys (33 h) against only 393 actual gate moments, one session hitting the whole suite 161 # times in a day while editing a single leaf crate. 59 % of edits land in `benilla-app`, which # nothing but the `benilla` bin depends on: the honest scope of a round is 1–3 crates, not 19. # # Scope rule — conservative by construction, unknown means FULL, never "probably fine": # crates//** → that crate (owner read off cargo metadata, not the dir name) # assets/ui/** → benilla-app (ui_script's shipped-UI tests read it at runtime) # *.md → no gate can change (gates.sh's docs-only rule) # anything else → escalate: exec scripts/gates.sh (workspace manifests, .cargo/, # rust-toolchain, scripts/, shaders outside crates, …) # Change set = fork point vs main + staged + unstaged + untracked — the round's work, not the last # edit. CHECK_FULL=1 skips straight to gates.sh. # # Same fail-fast discipline as gates.sh: never compose `cargo … | tail` pipelines by hand — the # pipe's exit code masks the gate's (that bug bit twice before gates.sh existed). set -uo pipefail # Gate the tree you are STANDING IN (gates.sh learned this; same rule here). here="$(cd "$(dirname "$0")/.." && pwd)" root="$(git rev-parse --show-toplevel 2>/dev/null || true)" [ -n "$root" ] && [ -f "$root/scripts/check.sh" ] || root="$here" cd "$root" || exit 1 if [ "${CHECK_FULL:-}" = "1" ]; then exec "$root/scripts/gates.sh" fi # ── The round's change set ─────────────────────────────────────────────────────────────────────── base="$(git merge-base HEAD main 2>/dev/null || git rev-parse HEAD)" changed="$( { git diff --name-only "$base" HEAD 2>/dev/null git diff --name-only HEAD 2>/dev/null git ls-files --others --exclude-standard 2>/dev/null; } | sort -u )" if [ -z "$changed" ]; then echo "check: no changes against main and a clean tree — nothing to verify" exit 0 fi # ── Map files → crate dirs; anything unmappable escalates to the full chain ────────────────────── dirs="" full_reason="" while IFS= read -r f; do case "$f" in docs/* | *.md) ;; # provably gate-inert (gates.sh's docs-only rule) assets/ui/*) dirs="$dirs benilla-app-DIR:crates/benilla-app" ;; crates/*/*) d="${f#crates/}"; dirs="$dirs DIR:crates/${d%%/*}" ;; *) full_reason="$f" ;; esac done <"$log" 2>&1; then echo "CHECK FAILED: $name" tail -30 "$log" exit 1 fi echo "check ok: $name" } run fmt cargo fmt --all -- --check run clippy cargo clippy $pflags --all-targets -- -D warnings run test env BENILLA_SKIP_LOG="$skips" cargo test $pflags # The data-gated tests skip without the install or the addon corpus, and libtest swallows the # line; the resolver logs each skip to $BENILLA_SKIP_LOG and this counts them (gates.sh says why). if [ -s "$skips" ]; then echo " test: $(wc -l <"$skips" | tr -d ' ') data-gated tests SKIPPED on this machine —" sort "$skips" | uniq -c | sort -rn | sed 's/^ *\([0-9]*\) \(.*\)/ \1 × \2/' echo " (they run where the data is: docs/CONTRIBUTING.md, \"Setting up\")" fi echo "CHECK GREEN (scoped: $pkgs)" echo " (land still pays the full chain once: scripts/gates.sh — memoized, so an already-gated tree is free)"