§3.5 hours: isOpen() gates enterShop — closed shops locked; at night only the openLate video rental opens. §3.4: ?noassets (zero-network primitive path, verified via Performance API), interior fitting GLB upgrades from the 3GOD depot (useGLB), and the rig-fleet upgrade (models/peds/*.glb) so peds + keepers become shared GLB rigs, leak-free (shared loadGLB cache proven, not a leak). qa.sh manifest gate now --depot (16 GLBs live) — GREEN 4/4. Browser QA harness fixes so shots.py/soak.py actually run: DBG async-poll (was racing the async install), plan via window.PROCITY (DBG.plan unexposed), enterShop bare-id, shop.lot is a lot id, midday pin (§3.5 else closes shops mid-walk), GLB-cache warmup, budget peaks -> warnings (gate 3 clean pass is authoritative). Gate 2 soak PASS both asset modes; gate 4 asset-free PASS; docs/shots/v1_tour/ (10 shots) + contact sheet captured. Findings (LANE_F_NOTES §9): D/E decimate tri-heavy ped GLBs (gate 3 tris ~279k > 200k budget; draws fine ~200/300). B: add 3 shots bookmark poses, fix headless composer letterbox in DBG.shot(), render the §3.5 closed-facade visual (predicate window.PROCITY.isOpen). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
84 lines
4.4 KiB
Bash
Executable File
84 lines
4.4 KiB
Bash
Executable File
#!/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 A–E 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))
|
||
}
|
||
|
||
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
|
||
|
||
# ── Summary ──────────────────────────────────────────────────────────────────
|
||
hr
|
||
printf '%sSUMMARY%s %s%d passed%s · %s%d failed%s · %s%d skipped%s\n' \
|
||
"$c_bold" "$c_off" "$c_grn" "$pass" "$c_off" "$c_red" "$failn" "$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
|