mirror of
https://github.com/Imbad0202/academic-research-skills.git
synced 2026-09-14 13:51:17 +08:00
90245a37b1
Every failing validation now closes with "see shared/<pattern>.md" so the user knows where to read field rationales. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
80 lines
2.4 KiB
Python
80 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Validate an ARS benchmark report against benchmark_report.schema.json.
|
|
|
|
Usage: python scripts/check_benchmark_report.py path/to/report.json
|
|
|
|
Exit 0 on pass (warnings may still be printed to stderr).
|
|
Exit 1 on validation failure.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import jsonschema
|
|
|
|
SCHEMA_PATH = Path(__file__).resolve().parent.parent / "shared" / "benchmark_report.schema.json"
|
|
|
|
|
|
def load_schema() -> dict:
|
|
return json.loads(SCHEMA_PATH.read_text(encoding="utf-8"))
|
|
|
|
|
|
def validate(report: dict) -> list[str]:
|
|
schema = load_schema()
|
|
validator = jsonschema.Draft202012Validator(schema)
|
|
return [f"{list(e.absolute_path)}: {e.message}" for e in validator.iter_errors(report)]
|
|
|
|
|
|
def warn_self_scored(report: dict) -> list[str]:
|
|
warnings = []
|
|
scoring = report.get("metrics", {}).get("scoring_independence")
|
|
if scoring == "self-scored":
|
|
warnings.append(
|
|
"WARNING: metrics.scoring_independence = 'self-scored'. "
|
|
"Self-scoring is permitted but a known reward-hacking risk. "
|
|
"Consider blind-scored or third-party-scored instead."
|
|
)
|
|
sample = report.get("human_baseline", {}).get("sample_size", 0)
|
|
if isinstance(sample, int) and 1 <= sample <= 2:
|
|
warnings.append(
|
|
f"WARNING: human_baseline.sample_size = {sample}. "
|
|
"n<=2 is dramatic, not statistical. Consider n>=5 or explicit disclosure in caveats."
|
|
)
|
|
return warnings
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("report", type=Path, help="Path to the benchmark report JSON")
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
report = json.loads(args.report.read_text(encoding="utf-8"))
|
|
except (FileNotFoundError, json.JSONDecodeError) as exc:
|
|
print(f"ERROR: failed to load {args.report}: {exc}")
|
|
return 1
|
|
|
|
errors = validate(report)
|
|
if errors:
|
|
for e in errors:
|
|
print(f"ERROR: {e}")
|
|
print(
|
|
f"\n{len(errors)} schema violation(s). "
|
|
f"See shared/benchmark_report_pattern.md for field rationale.",
|
|
file=sys.stderr,
|
|
)
|
|
return 1
|
|
|
|
for w in warn_self_scored(report):
|
|
print(w, file=sys.stderr)
|
|
|
|
print("OK: benchmark report validates.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|