PROCITY/tools/qa.sh
m3ultra 5700954212 Lane F R6 F1: v2 flag enforcement harness (flags-off regression + smokes)
tools/flags_check.py — the machine version of the R5 review, headless, self-contained
server, ~90s:
 • flags-off regression (prime-law enforcement): plan fingerprint == golden 0x3fa36874,
   all v2 subsystems inactive, street view within v1 budget (<=300 draws / <=200k tris),
   within 40% of the v1.1 snapshot, 0 console errors.
 • per-flag smoke (winmap/dig/roster, +plansrc auto-detected when A lands): boot flag-on,
   cross >=2 chunks, enter an interior; dig also opens+closes a riffle. 0 console errors.
 • all-on combo (flag-composition law, decision #4): every landed flag on at once.

Wired into qa.sh as a WARN-level gate (strict in r7): --no-flags skips fast; auto-skips
without the Playwright venv; a soft_skip so it never trips --strict readiness. Current tree:
all smokes GREEN, regression clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:38:42 +10:00

109 lines
6.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# PROCITY Lane F — the QA gate runner (CITY_SPEC / LANE_F acceptance).
#
# tools/qa.sh run every gate whose inputs have landed; skip the rest
# tools/qa.sh --strict also FAIL on any still-pending lane deliverable (use at v1 sign-off)
#
# Design: F runs before AE finish. A gate whose target file does not exist yet is reported
# SKIPPED (yellow), not failed — so this is safe to run continuously as lanes land. Once every
# lane is in, `--strict` turns the skips into hard failures: that is the v1 readiness gate.
#
# Gates:
# 1. scaffold_check.mjs — scaffold + PRNG determinism law + lane-readiness matrix (F-owned)
# 2. citygen selfcheck — node web/js/citygen/selfcheck.js (Lane A ships it)
# 3. manifest validator — python3 pipeline/validate_manifest.py (Lane E ships it)
#
# Browser-driven gates (determinism-PNG, 10-min soak, budget-HUD, ?noassets run) need the running
# game; they live in tools/soak.md + tools/shots.md and run once Lane B's index.html lands.
set -uo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
STRICT=0
[ "${1:-}" = "--strict" ] && STRICT=1
pass=0; failn=0; skip=0
c_red=$'\033[31m'; c_grn=$'\033[32m'; c_yel=$'\033[33m'; c_bold=$'\033[1m'; c_off=$'\033[0m'
hr() { printf '%s\n' "────────────────────────────────────────────────────────"; }
run_gate() { # run_gate "name" cmd...
local name="$1"; shift
printf '%s▶ %s%s\n' "$c_bold" "$name" "$c_off"
if "$@"; then printf '%s ✓ PASS%s %s\n\n' "$c_grn" "$c_off" "$name"; pass=$((pass+1));
else printf '%s ✗ FAIL%s %s\n\n' "$c_red" "$c_off" "$name"; failn=$((failn+1)); fi
}
skip_gate() { # skip_gate "name" "reason"
printf '%s▶ %s%s\n' "$c_bold" "$1" "$c_off"
printf '%s ⊘ SKIP%s %s\n\n' "$c_yel" "$c_off" "$2"
skip=$((skip+1))
}
warnn=0
soft_skip() { # non-blocking skip for a warn-level gate — does NOT trip --strict readiness
printf '%s▶ %s%s\n' "$c_bold" "$1" "$c_off"
printf '%s ⊘ SKIP%s %s (warn-level, non-blocking)\n\n' "$c_yel" "$c_off" "$2"
}
warn_gate() { # warn_gate "name" cmd... — runs, but a failure is a WARN not a FAIL (round-6 policy)
local name="$1"; shift
printf '%s▶ %s%s (warn-level)\n' "$c_bold" "$name" "$c_off"
if "$@"; then printf '%s ✓ PASS%s %s\n\n' "$c_grn" "$c_off" "$name"; pass=$((pass+1));
else printf '%s ! WARN%s %s (non-blocking this round — strict in r7)\n\n' "$c_yel" "$c_off" "$name"; warnn=$((warnn+1)); fi
}
printf '%sPROCITY QA GATES%s (%s)\n' "$c_bold" "$c_off" "$([ $STRICT = 1 ] && echo strict || echo lenient)"
hr
# ── Gate 1: scaffold + determinism + readiness (always) ──────────────────────
run_gate "scaffold_check (scaffold · PRNG determinism · readiness matrix)" \
node tools/qa/scaffold_check.mjs
# ── Gate 1b: cross-lane consistency (plan ↔ registry ↔ assets ↔ manifest) ────
# Self-skips (exit 0) until Lane A's plan.js + registry.js exist.
run_gate "consistency (plan ↔ registry ↔ assets ↔ manifest)" \
node tools/qa/consistency_check.mjs
# ── Gate 2: Lane A citygen selfcheck ─────────────────────────────────────────
if [ -f web/js/citygen/selfcheck.js ]; then
run_gate "citygen selfcheck (determinism · <100ms · lots/shops integrity)" \
node web/js/citygen/selfcheck.js
else
skip_gate "citygen selfcheck" "web/js/citygen/selfcheck.js not landed yet (Lane A)"
fi
# ── Gate 3: Lane E manifest validator ────────────────────────────────────────
# [Lane F R3] --depot: the 16 GLBs are published + live on the 3GOD depot (Fable, 2026-07-14), so the
# gate now REQUIRES them reachable (was a soft local-only check). Override the endpoint with GOD3_DEPOT
# (tailnet path) if digalot.fyi is unreachable; the validator falls back to the manifest's depot field.
if [ -f pipeline/validate_manifest.py ]; then
run_gate "manifest validator (files exist · footprints sane · GLBs live on depot · JSON parses)" \
python3 pipeline/validate_manifest.py --depot
else
skip_gate "manifest validator" "pipeline/validate_manifest.py not landed yet (Lane E)"
fi
# ── Gate 4 (warn-level, round 6): v2 flag enforcement harness ────────────────
# Flags-off regression (prime-law) + per-flag + all-on-combo smokes. Needs the Playwright venv +
# a browser (self-contained server), auto-skips where absent. Non-blocking this round; strict in r7.
# Skip explicitly with --no-flags (fast determinism-only runs).
FLAGS_SKIP=0; for a in "$@"; do [ "$a" = "--no-flags" ] && FLAGS_SKIP=1; done
if [ "$FLAGS_SKIP" = 1 ]; then
soft_skip "v2 flags harness" "--no-flags"
elif [ -x tools/.venv/bin/python ] && tools/.venv/bin/python -c "import playwright" 2>/dev/null; then
warn_gate "v2 flags harness (flags-off regression · per-flag · all-on combo)" \
tools/.venv/bin/python tools/flags_check.py
else
soft_skip "v2 flags harness" "Playwright venv absent (python3 -m venv tools/.venv && …/pip install playwright)"
fi
# ── Summary ──────────────────────────────────────────────────────────────────
hr
printf '%sSUMMARY%s %s%d passed%s · %s%d failed%s · %s%d warn%s · %s%d skipped%s\n' \
"$c_bold" "$c_off" "$c_grn" "$pass" "$c_off" "$c_red" "$failn" "$c_off" "$c_yel" "$warnn" "$c_off" "$c_yel" "$skip" "$c_off"
if [ "$failn" -gt 0 ]; then
printf '%s● QA RED%s — fix the failing gate(s) above.\n' "$c_red" "$c_off"; exit 1
fi
if [ "$STRICT" = 1 ] && [ "$skip" -gt 0 ]; then
printf '%s● QA NOT READY%s — %d gate(s) still pending; not v1 yet.\n' "$c_yel" "$c_off" "$skip"; exit 2
fi
printf '%s● QA GREEN%s — every landed gate passed.\n' "$c_grn" "$c_off"; exit 0