Spaces:
Running
Running
File size: 3,959 Bytes
e2d54c9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | """Entry point for every experiment node.
The run command is a fixed contract -- `bash run.sh` on every node, which calls
`python -m repro.main`. What a node *does* is decided entirely by the committed
file `repro/config/active.json`, never by the command line or the environment.
Exit code is 0 only if every enabled stage's verdict gate passes.
"""
from __future__ import annotations
import importlib
import json
import sys
import time
from pathlib import Path
from repro.lib import report
from repro.lib.verdict import Verdict
CONFIG_PATH = Path("repro/config/active.json")
# A stage named "foo" is the module repro.stages.foo exposing
# `run(params) -> Verdict | list[Verdict]`. Resolution is by name so that
# sibling branches can add their own stage modules without colliding.
STAGE_PACKAGE = "repro.stages"
def resolve_stage(name: str):
if not name.replace("_", "").isalnum():
raise SystemExit(f"illegal stage name {name!r}")
try:
return importlib.import_module(f"{STAGE_PACKAGE}.{name}")
except ModuleNotFoundError as exc:
raise SystemExit(f"stage {name!r} has no module {STAGE_PACKAGE}.{name}: {exc}")
def load_config() -> dict:
if not CONFIG_PATH.exists():
raise SystemExit(f"missing {CONFIG_PATH} -- every node must commit its stage config")
cfg = json.loads(CONFIG_PATH.read_text())
if not cfg.get("stages"):
raise SystemExit(f"{CONFIG_PATH} lists no stages")
return cfg
def main() -> int:
t0 = time.time()
cfg = load_config()
sha = report.git_sha()
cpu = report.cpu_info()
print("=" * 78)
print("Reproduction: 'Curated Synthetic Data Doesn't Have to Collapse'")
print(" (arXiv:2605.07724, OpenReview kwvtSA9ed3)")
print("=" * 78)
report.kv("node", cfg.get("node", "?"))
report.kv("git sha", sha)
report.kv("stages", ", ".join(cfg.get("stages", [])))
report.kv("cpu: logical cores visible", cpu.get("os_cpu_count"))
report.kv("cpu: cores in affinity mask", cpu.get("sched_getaffinity"))
report.kv("cpu: model", cpu.get("model_name", "n/a"))
report.kv("cpu: cgroup cpu.max", cpu.get("cgroup_cpu_max", "n/a"))
report.kv("estimated cores required (declared)", cfg.get("estimated_cores", "?"))
report.kv("compute target (declared)", cfg.get("compute_target", "?"))
verdicts: list[Verdict] = []
for name in cfg.get("stages", []):
mod = resolve_stage(name)
with report.Section(f"stage: {name}") as sec:
out = mod.run(cfg.get("params", {}).get(name, {}))
got = out if isinstance(out, list) else [out]
for v in got:
v.runtime_s = sec.seconds
v.print_summary()
verdicts.extend(got)
summary = {
"paper": "arXiv:2605.07724",
"openreview": "kwvtSA9ed3",
"node": cfg.get("node", "?"),
"git_sha": sha,
"stages": cfg.get("stages", []),
"cpu": cpu,
"declared_estimated_cores": cfg.get("estimated_cores"),
"declared_compute_target": cfg.get("compute_target"),
"total_runtime_s": time.time() - t0,
"verdicts": [v.to_dict() for v in verdicts],
}
gates = {v.claim_id: v.gate()[0] for v in verdicts}
summary["all_gates_pass"] = all(gates.values())
out_path = report.write_json(report.ARTIFACTS / "verdicts.json", summary)
print("\n" + "=" * 78)
print("SUMMARY")
print("=" * 78)
for v in verdicts:
ok = "GATE-PASS" if v.gate()[0] else "GATE-FAIL"
print(f" {v.claim_id:<28} {v.status:<10} {ok}")
print(f"\n artifacts: {out_path}")
print(f" total runtime: {summary['total_runtime_s']:.1f}s")
if not summary["all_gates_pass"]:
print("\n FAILED: at least one verdict is not supported by its own evidence.")
return 1
print("\n OK: every recorded verdict is supported by its own evidence.")
return 0
if __name__ == "__main__":
sys.exit(main())
|