#!/usr/bin/env python3 """Sparrow judge — headless, behavioral, the real quality gate. Runs the pipeline on a fixed sweep of synthetic frames (same recipe as `scene.py frames`), measures what the product promises, and prints PASS/FAIL lines that name the owning file (they feed the build-gate mail). pixi run judge # or: pixi run python judge.py — prints + judge_report.md Exit code 0 only when every check is green. """ import json import sys from pathlib import Path import cv2 import numpy as np ROOT = Path(__file__).resolve().parent sys.path.insert(0, str(ROOT)) import core # noqa: E402 import scene # noqa: E402 # Product-grade thresholds the SPRINT must hit (seed starts failing on # purpose — that is the backlog). Raise with care, in a PR, with a talk. THRESHOLDS = { "feature_density": 130, # avg features/frame — features.py owner "tracking_continuity": 0.90, # fraction of tracks surviving 2+ frames — tracker.py "jitter_px": 1.5, # median frame-to-frame residual, px — tracker.py "map_growth": [50, 900], # sparse map point count band at t=3s — map.py } def density_check(frame): pts, _ = core.extract(frame) return len(pts) def run(): lines = [] nsamp = 40 density = [] pipe = core.Pipeline() continuity_survive = continuity_total = 0 res_hist = [] prev_pts = None prev_gray = None import core as _c for i in range(nsamp): t = i / 10.0 f = scene.render(t) res = pipe.on_frame(f) density.append(res["features"]) gray = cv2.cvtColor(f, cv2.COLOR_BGR2GRAY) # plain continuity stats via the seed flow for reporting if prev_pts is not None and len(prev_pts) >= 6: cur, matched, lost = core.step(prev_gray, gray, prev_pts) continuity_survive += len(cur) continuity_total += len(prev_pts) pts, _ = core.extract(f) if prev_pts is not None and len(prev_pts) >= 4: cur, matched_prev, lost = core.step(prev_gray, gray, prev_pts[-len(prev_pts):]) d = np.linalg.norm(cur[: len(matched_prev)] - matched_prev, axis=1) if len(cur) else np.array([9e9]) res_hist.append(float(np.median(d))) prev_pts = pts.astype(np.float32) if len(pts) else None prev_gray = gray avg_density = float(np.mean(density)) cont = continuity_survive / max(1, continuity_total) jitter = float(np.median(res_hist)) if res_hist else 9e9 snap = pipe.map.snapshot() map_cnt = snap.get("count", 0) def check(name, metric, thresh, owner): if isinstance(thresh, list): ok = thresh[0] <= metric <= thresh[1] verdict = f"{metric:.0f} outside [{thresh[0]}, {thresh[1]}]" else: ok = metric >= thresh if name != "jitter_px" else metric <= thresh verdict = f"{metric:.2f} vs {'<=' if name == 'jitter_px' else '>='} {thresh}" lines.append( (f"PASS {name}" if ok else f"FAIL {owner}: {name}: {verdict} ") ) return ok check("feature_density", avg_density, THRESHOLDS["feature_density"], "features.py") check("tracking_continuity", cont, THRESHOLDS["tracking_continuity"], "tracker.py") check("jitter_px", jitter, THRESHOLDS["jitter_px"], "tracker.py") check("map_growth", float(map_cnt), THRESHOLDS["map_growth"], "map.py") fail = sum(1 for l in lines if l.startswith("FAIL")) report = "\n".join(lines) (ROOT / "judge_report.md").write_text(f"# judge (seed)\n\n{report}\n") print(f"sparrow judge: {len(lines) - fail} pass, {fail} fail") for l in lines: print((" " + l)) return 1 if fail else 0 if __name__ == "__main__": sys.exit(run())