#!/usr/bin/env python3 """Build the compact 21-model accuracy CSV from retained audited values.""" from __future__ import annotations import argparse import csv import json import os import tempfile from pathlib import Path FIELDS = [ "model_id", "model_name", "metric", "fp32", "quantized", "delta", "published_comparison", ] def load_rows(root: Path) -> list[dict[str, str]]: source = root / "reports/accuracy/model_accuracy_values.json" payload = json.loads(source.read_text(encoding="utf-8")) if payload.get("schema_version") != "1.0": raise ValueError("unsupported model accuracy value schema") records = payload.get("models") if not isinstance(records, list) or len(records) != 21: raise ValueError("model accuracy source must contain 21 records") rows = [{field: str(record.get(field, "")) for field in FIELDS} for record in records] for row in rows: if not row["published_comparison"].strip(): row["published_comparison"] = "공개 수치 없음." registry = { row["model_id"]: row for row in csv.DictReader((root / "model_registry.csv").open(newline="", encoding="utf-8")) if row["eligibility"] == "ELIGIBLE" } if {row["model_id"] for row in rows} != set(registry): raise ValueError("accuracy source model IDs differ from active registry") for row in rows: if row["model_name"] != registry[row["model_id"]]["model_name"]: raise ValueError(f"model name differs from registry: {row['model_id']}") return rows def atomic_write_csv(path: Path, rows: list[dict[str, str]]) -> None: path.parent.mkdir(parents=True, exist_ok=True) fd, temporary = tempfile.mkstemp(prefix=path.name + ".", suffix=".tmp", dir=path.parent) try: with os.fdopen(fd, "w", encoding="utf-8", newline="") as handle: writer = csv.DictWriter(handle, fieldnames=FIELDS, lineterminator="\n") writer.writeheader() writer.writerows(rows) os.replace(temporary, path) except BaseException: Path(temporary).unlink(missing_ok=True) raise def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--repo-root", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) args = parser.parse_args() root = args.repo_root.resolve() output = args.output if args.output.is_absolute() else root / args.output records = load_rows(root) atomic_write_csv(output, records) print(json.dumps({ "status": "PASS", "output": str(output), "row_count": len(records), "source": "reports/accuracy/model_accuracy_values.json", "model_runtime_executed": False, "dataset_evaluation_executed": False, }, sort_keys=True)) return 0 if __name__ == "__main__": raise SystemExit(main())