Spaces:
Sleeping
Sleeping
File size: 2,921 Bytes
a4f876a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | """R0-4 — post-deploy FRONTEND gate.
Three test rounds were invalidated by a stale frontend (Vercel promote
skipped twice; an outdated URL once). This gate verifies the ARTIFACT the
testers actually load: fetch the canonical production URL, locate the built
bundle, and assert it carries the current engine's markers and points at the
right backend. Run it after every Vercel promote — a failure means testers
would be looking at old code.
Pure stdlib (no pip installs in CI).
Usage:
python verify_live_frontend.py [base_url]
# default: https://room-editor-9y3b.vercel.app
Exit 0 = the served frontend is current; non-zero = block/alert.
"""
import re
import sys
import urllib.request
CANONICAL_URL = "https://room-editor-9y3b.vercel.app"
BACKEND_HOST = "modventures-room-visualizer.hf.space"
# Marker inventory: object property names survive minification; function
# names do not. Keep one marker per shipped feature generation so a stale
# build is identifiable by WHICH markers are missing.
ENGINE_MARKERS = [
("defaultRotation", "P1-4 rotation consumption"),
("keepRug", "R3-3 rug toggle"),
("tileWidthM", "R1-3/R2-1 metric sizing"),
("groutFrac", "R2-3 procedural cells"),
("rugFlags", "R3-3 rug flags"),
("Classic Checkered", "catalog present"),
("Calacatta Marble", "R2-2 seamless pack (2026-06-12)"),
("viz2d/convert", "backend API wiring"),
(BACKEND_HOST, "points at the canonical backend"),
]
def fetch(url: str, timeout: int = 30) -> str:
req = urllib.request.Request(url, headers={"User-Agent": "verify-live-frontend"})
with urllib.request.urlopen(req, timeout=timeout) as r:
return r.read().decode("utf-8", errors="replace")
def main() -> int:
base = sys.argv[1] if len(sys.argv) > 1 else CANONICAL_URL
print(f"frontend gate target: {base}", flush=True)
html = fetch(base)
ok = True
title = re.search(r"<title>([^<]*)</title>", html)
title_ok = bool(title) and "BAETES" in title.group(1)
print(f" [{'PASS' if title_ok else 'FAIL'}] title is the current app "
f"({title.group(1) if title else 'none'})")
ok &= title_ok
asset = re.search(r"assets/index-[A-Za-z0-9_-]+\.js", html)
if not asset:
print(" [FAIL] no built index-*.js asset referenced — not a Vite build?")
raise SystemExit("FRONTEND GATE FAILED")
print(f" bundle: {asset.group(0)}")
bundle = fetch(f"{base}/{asset.group(0)}", timeout=60)
for marker, why in ENGINE_MARKERS:
passed = marker in bundle
print(f" [{'PASS' if passed else 'FAIL'}] {marker} ({why})")
ok &= passed
if not ok:
print("\nFRONTEND GATE FAILED — the served bundle is stale or "
"mis-deployed. Did the Vercel production promote happen?")
return 1
print("\nFRONTEND GATE PASSED")
return 0
if __name__ == "__main__":
raise SystemExit(main())
|