#!/usr/bin/env python """Build reproducibility/run_index.md from every run manifest found locally and on the listed nodes (read-only).""" import glob, json, subprocess, sys from pathlib import Path NODES = sys.argv[1:] or ["M3U96a", "M3U96b", "M2U64", "M4M64c", "M4M64a", "M5M36", "M4BP48", "M4BP36", "m4mn"] rows = {} for mp in glob.glob("experiments/runs/*/manifest.json"): m = json.load(open(mp)); rows[m["run_id"]] = (m, "laptop") for n in NODES: try: out = subprocess.run(["ssh", "-o", "ConnectTimeout=8", n, "cat ~/wp31/prisme-slm/experiments/runs/*/manifest.json 2>/dev/null | python3 -c 'import sys,json; d=sys.stdin.read().replace(\"}\\n{\",\"}\\x00{\"); print(\"\\x00\".join(d.split(\"\\x00\")))'"], capture_output=True, text=True, timeout=40).stdout for chunk in out.split("\x00"): chunk = chunk.strip() if chunk: try: m = json.loads(chunk); rows.setdefault(m["run_id"], (m, n)) except json.JSONDecodeError: pass except Exception as e: # noqa: BLE001 print("skip", n, e) lines = ["# Run index (auto-generated by scripts/run_index.py)", "", "| run_id | state | host | device | wall s | train tokens | peak mem (GB) | commit | notes |", "|---|---|---|---|---|---|---|---|---|"] for rid, (m, where) in sorted(rows.items()): pm = m.get("peak_memory_bytes"); pm = f"{pm/1e9:.1f}" if isinstance(pm, (int, float)) and pm else "" lines.append(f"| {rid} | {m.get('state','')} | {where} | {m.get('device','')} | {m.get('wall_seconds','')} | {m.get('train_tokens','')} | {pm} | {str(m.get('code_commit',''))[:8]} | {m.get('mode','')} |") Path("reproducibility/run_index.md").write_text("\n".join(lines) + "\n") print(len(rows), "runs indexed")