Spaces:
Sleeping
Sleeping
| """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()) | |