"""Check the selected release's UI bytes and case contract, excluding backend code.""" import argparse import hashlib import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] CASE_KEYS = ["id", "route", "route_title", "title", "prompt", "expected", "image", "source", "image_sha256", "difficulty", "validation", "image_size", "expected_available", "gt_coord", "gt", "visual_prompt"] def fingerprint(root): rows = json.loads((root / "data/cases.json").read_text()) paths = ["app.py", "grounding_demo/console.py", "grounding_demo/catalog.py", "grounding_demo/protocol.py", "grounding_demo/render.py"] paths += [str(path.relative_to(root)) for path in (root / "assets").iterdir() if path.is_file()] paths += [row["image"] for row in rows] normalized = [{key: row.get(key) for key in CASE_KEYS} for row in rows] return { "files": {name: hashlib.sha256((root / name).read_bytes()).hexdigest() for name in sorted(paths)}, "case_contract_sha256": hashlib.sha256(json.dumps(normalized, sort_keys=True, ensure_ascii=False).encode()).hexdigest(), "cases": len(rows), "routes": len({row["route"] for row in rows}), } def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--reference", type=Path, help="Original project; compare then create lock without overwrite") args = parser.parse_args() current = fingerprint(ROOT) lock = ROOT / "docs/ui_case_pool_22_lock.json" if not lock.exists(): lock = ROOT / "docs/ui_studio_r8_lock.json" if not lock.exists(): lock = ROOT / "docs/ui_paper_r7_lock.json" if not lock.exists(): lock = ROOT / "docs/ui_lock.json" if args.reference: original = fingerprint(args.reference.resolve()) if current != original: raise SystemExit("FAIL: UI/assets/case contract differ from reference") with lock.open("x", encoding="utf-8") as f: json.dump(current, f, indent=2, ensure_ascii=False) f.write("\n") else: if current != json.loads(lock.read_text()): raise SystemExit("FAIL: UI/assets/case contract differ from selected release lock") print(f"PASS: {len(current['files'])} locked UI/assets/images; {current['routes']} routes; {current['cases']} cases") if __name__ == "__main__": main()