"""Summarize Simam3D run manifests for reproducible backend comparisons.""" from __future__ import annotations import argparse import json from pathlib import Path def _mean(values) -> float | None: numbers = [float(value) for value in values if value is not None] return sum(numbers) / len(numbers) if numbers else None def summarize_manifest(manifest: dict, path: str | Path = "") -> dict: metrics = manifest.get("metrics") or {} reprojection = metrics.get("reprojection_consistency") or [] coverage = metrics.get("projection_coverage") or [] return { "manifest": str(path), "run_id": manifest.get("run_id"), "status": manifest.get("status", "completed"), "stage": manifest.get("stage"), "backend": manifest.get("backend"), "runtime": manifest.get("runtime"), "view_count": manifest.get("view_count"), "fused_point_count": metrics.get("fused_point_count"), "projection_coverage_mean": _mean(coverage), "reprojection_mae_mean": _mean(item.get("mean_absolute_error") for item in reprojection), "fallback_error": metrics.get("fallback_error"), "failure_error": manifest.get("error"), "claims": manifest.get("claims", {}), } def find_manifests(root: Path) -> list[Path]: if root.is_file(): return [root] return sorted(set(root.rglob("*_run.json")) | set(root.rglob("*_failure.json"))) def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("path", type=Path, help="A run manifest or directory containing manifests") args = parser.parse_args(argv) rows = [] for path in find_manifests(args.path): try: manifest = json.loads(path.read_text(encoding="utf-8")) rows.append(summarize_manifest(manifest, path)) except (OSError, json.JSONDecodeError) as exc: print(f"warning: skipped {path}: {exc}") print(json.dumps(rows, indent=2)) return 0 if rows else 1 if __name__ == "__main__": raise SystemExit(main())