guts/tools/qa.sh
jing 4ccf5edcc0 [lane F] Round 1 integration + ROUND2 instructions: the game is a game
Wired B's player/combat + event pump, D's assets, C's level pick into boot.
Fixed qa ESM gate (node --check no-op, found by B) + added spline selfcheck.
TECH: world contract FROZEN v1.1, bus events ratified, colorspace + crest-speed
laws (CREST_FACTOR 1.6 — B proved surfing lost to throttle at 1.0). Stub complies.
Verified integrated build via 60s stepped sim: 9 draws, 0 errors, 0 asset misses;
one known gap (fiction-id spawn resolve) confirmed and assigned as B's top item.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 14:39:02 +10:00

55 lines
2.3 KiB
Bash
Executable File

#!/bin/bash
# tools/qa.sh (Lane F) — the gate. Run before you finish a session; leave it GREEN.
# Dependency-free: bash + node + python3. Gates accumulate each round.
set -u
cd "$(dirname "$0")/.."
FAIL=0
red() { printf '\033[31m✗ %s\033[0m\n' "$1"; FAIL=1; }
green() { printf '\033[32m✓ %s\033[0m\n' "$1"; }
# 1. every JS module parses.
# NB: plain `node --check` exits 0 on ANY file containing import/export (ESM detection
# no-op — found by Lane B round 1, verified on node v26). Must force module parsing.
JSBAD=0
while IFS= read -r -d '' f; do
node --check --input-type=module < "$f" 2>/dev/null || { echo "SYNTAX: $f"; node --check --input-type=module < "$f"; JSBAD=1; }
done < <(find web/js -name '*.js' -print0)
[ "$JSBAD" = 0 ] && green "node --check (ESM): all web/js modules parse" || red "JS syntax errors"
# 2. determinism law: Math.random only in core/rng.js
RAND=$(grep -rn 'Math\.random' web/js --include='*.js' | grep -v 'core/rng.js' || true)
if [ -n "$RAND" ]; then red "Math.random outside core/rng.js:"; echo "$RAND"; else green "determinism: no stray Math.random"; fi
# 3. level JSONs parse + minimal keys
LVLBAD=0
for f in web/js/levels/*.json; do
[ -e "$f" ] || continue
python3 - "$f" <<'PY' || LVLBAD=1
import json, sys
d = json.load(open(sys.argv[1]))
assert d.get("id") and isinstance(d.get("seed"), int) and d.get("segments"), "missing id/seed/segments"
PY
done
[ "$LVLBAD" = 0 ] && green "level JSONs valid" || red "level JSON errors"
# 4. Lane C selfcheck (when it exists)
if [ -f web/js/levels/index.js ]; then
node web/js/levels/index.js --selfcheck && green "levels selfcheck" || red "levels selfcheck failed"
fi
# 4b. Lane A world math (headless; no three.js needed)
if [ -f web/js/world/spline.js ]; then
node web/js/world/spline.js --selfcheck >/dev/null 2>&1 && green "world selfcheck" || red "world selfcheck failed"
fi
# 5. Lane D manifest validation (when it exists)
if [ -f pipeline/validate_manifest.py ]; then
python3 pipeline/validate_manifest.py && green "manifest valid" || red "manifest errors"
fi
# 6. vendor present (the game must run offline)
[ -f web/vendor/three.module.js ] && green "vendor: three r175 present" || red "web/vendor/three.module.js missing"
[ "$FAIL" = 0 ] && printf '\033[32mQA GREEN\033[0m\n' || printf '\033[31mQA RED\033[0m\n'
exit $FAIL