#!/usr/bin/env python """Issue 5 structure gate + capacity summarizer. Applies the gate rule from issue 1's FP8 misread to every recorded request and folds a run directory into the capacity matrix row: per reference count, wall time, peak VRAM, and the server-reported peak. Gate rule (a run only counts when structurally sound): opaque_fraction >= 0.99 AND mean(rgb_std) >= 10 Broken FP8 output measured opaque 0.008-0.035 with flat grey RGB (std of a few); the BF16 path is 100% opaque with healthy channel spread. Usage: gate.py RUN_DIR [RUN_DIR ...] # reads matrix.json / matrix-*.json """ from __future__ import annotations import argparse import json import pathlib import re def peak_vram_mb(vram_log: pathlib.Path) -> int | None: if not vram_log.exists(): return None peak = 0 for line in vram_log.read_text().splitlines(): match = re.match(r"\s*(\d+)\s+MiB\s*,", line) or re.match(r"\s*(\d+),", line) if match: peak = max(peak, int(match.group(1))) return peak or None def server_peak_mb(serve_log: pathlib.Path) -> int | None: if not serve_log.exists(): return None peaks = [int(m) for m in re.findall(r"peak.*?(\d[\d,]+)\s*MB", serve_log.read_text())] if not peaks: return None return max(peaks) def gate(structure: dict) -> bool: return ( structure["opaque_fraction"] >= 0.99 and sum(structure["rgb_std"]) / len(structure["rgb_std"]) >= 10 ) def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("runs", nargs="+", type=pathlib.Path) args = parser.parse_args() for run_dir in args.runs: records: list[dict] = [] for candidate in sorted(run_dir.glob("matrix*.json")): records.extend(json.loads(candidate.read_text())) by_refs: dict[int, list[dict]] = {} for rec in records: by_refs.setdefault(rec.get("n_references", 0), []).append(rec) print(f"== {run_dir.name} ==") all_pass = bool(records) for n_refs in sorted(by_refs): rows = by_refs[n_refs] walls = [r["wall_s"] for r in rows if "wall_s" in r] gates = [gate(r["structure"]) for r in rows if "structure" in r] row_pass = bool(rows) and all(gates) and len(gates) == len(rows) all_pass = all_pass and row_pass print( f" {n_refs}-ref: n={len(rows)} gate={'PASS' if row_pass else 'FAIL'} " f"wall {min(walls):.1f}-{max(walls):.1f}s" + (f" (mean {sum(walls) / len(walls):.1f}s)" if walls else "") ) for rec in rows: s = rec.get("structure") tag = "" if s is None else (" ok" if gate(s) else " BROKEN") err = f" error={rec['error'][:80]}" if rec.get("error") else "" print( f" {rec.get('fixture_id')} s{rec.get('seed')}: " f"{rec.get('wall_s')}s {json.dumps(s) if s else 'no-image'}{tag}{err}" ) peak = peak_vram_mb(run_dir / "vram.log") server_peak = server_peak_mb(run_dir / "serve.log") print(f" nvidia-smi peak: {peak} MiB; server peak: {server_peak} MB") print(f" STRUCTURE GATE: {'PASS' if all_pass else 'FAIL'}") return 0 if __name__ == "__main__": raise SystemExit(main())