Viewing files at commit 1dc7410826b4Commit detailsView latest

Browse files
scripts/public_readiness.py 160 lines · 5.4 KB · python
1
#!/usr/bin/env python3
2
"""Run the mechanical checks for a public benchmark drop.
3
4
This script does not run benchmarks. It takes the JSONL files already intended
5
for publication and writes a small readiness bundle:
6
7
- publish_gate.txt: hard mechanical gate output
8
- benchmark_stats.md: bootstrap confidence intervals for the same JSONL files
9
- opportunities.md / opportunities.json: ranked backlog from the same results
10
- manifest.json: exact inputs, commands, exit codes, and generated paths
11
"""
12
13
from __future__ import annotations
14
15
import argparse
16
import contextlib
17
import io
18
import json
19
import subprocess
20
import sys
21
from datetime import datetime, timezone
22
from pathlib import Path
23
from typing import Any
24
25
import opportunities
26
import publish_gate
27
28
29
ROOT = Path(__file__).resolve().parents[1]
30
DEFAULT_RESULTS = ROOT / "results"
31
32
33
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
34
    parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
35
    parser.add_argument(
36
        "jsonl",
37
        nargs="*",
38
        type=Path,
39
        help="Result JSONL files to publish. Defaults to latest JSONL files in --results.",
40
    )
41
    parser.add_argument("--results", type=Path, default=DEFAULT_RESULTS)
42
    parser.add_argument(
43
        "--out-dir",
44
        type=Path,
45
        help="Directory for readiness reports. Default: <results>/public-readiness.",
46
    )
47
    parser.add_argument("--bootstrap-samples", type=int, default=2000)
48
    parser.add_argument("--confidence", type=float, default=0.95)
49
    parser.add_argument("--skip-stats", action="store_true")
50
    parser.add_argument("--skip-opportunities", action="store_true")
51
    return parser.parse_args(argv)
52
53
54
def discover_inputs(results: Path) -> list[Path]:
55
    candidates = [
56
        results / "latest.jsonl",
57
        results / "latest.mount.jsonl",
58
        results / "parallel-contention" / "latest.jsonl",
59
        results / "conformance" / "latest.jsonl",  # vcs_conformance.py --output (publish_gate check 14)
60
    ]
61
    return [path for path in candidates if path.exists()]
62
63
64
def write_text(path: Path, text: str) -> str:
65
    path.parent.mkdir(parents=True, exist_ok=True)
66
    path.write_text(text)
67
    return str(path)
68
69
70
def run_publish_gate(inputs: list[Path], out_dir: Path) -> dict[str, Any]:
71
    buf = io.StringIO()
72
    with contextlib.redirect_stdout(buf):
73
        exit_code = publish_gate.main([str(path) for path in inputs])
74
    return {
75
        "name": "publish_gate",
76
        "exit_code": exit_code,
77
        "path": write_text(out_dir / "publish_gate.txt", buf.getvalue()),
78
    }
79
80
81
def run_benchmark_stats(
82
    inputs: list[Path],
83
    out_dir: Path,
84
    bootstrap_samples: int,
85
    confidence: float,
86
) -> dict[str, Any]:
87
    command = [
88
        sys.executable,
89
        str(ROOT / "scripts" / "benchmark_stats.py"),
90
        *[str(path) for path in inputs],
91
        "--bootstrap-samples",
92
        str(bootstrap_samples),
93
        "--confidence",
94
        str(confidence),
95
    ]
96
    proc = subprocess.run(command, cwd=ROOT, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
97
    stats_path = write_text(out_dir / "benchmark_stats.md", proc.stdout)
98
    stderr_path = None
99
    if proc.stderr:
100
        stderr_path = write_text(out_dir / "benchmark_stats.stderr.txt", proc.stderr)
101
    return {
102
        "name": "benchmark_stats",
103
        "exit_code": proc.returncode,
104
        "command": command,
105
        "path": stats_path,
106
        "stderr_path": stderr_path,
107
    }
108
109
110
def run_opportunities(results: Path, inputs: list[Path], out_dir: Path) -> dict[str, Any]:
111
    report, entries = opportunities.generate_report(results, input_paths=inputs)
112
    report_path = write_text(out_dir / "opportunities.md", report)
113
    json_path = out_dir / "opportunities.json"
114
    json_path.write_text(json.dumps(entries, indent=2, sort_keys=True) + "\n")
115
    return {
116
        "name": "opportunities",
117
        "exit_code": 0,
118
        "path": str(report_path),
119
        "json_path": str(json_path),
120
        "entry_count": len(entries),
121
    }
122
123
124
def main(argv: list[str] | None = None) -> int:
125
    args = parse_args(argv)
126
    results = args.results.resolve()
127
    out_dir = (args.out_dir or (results / "public-readiness")).resolve()
128
    inputs = [path.resolve() for path in (args.jsonl or discover_inputs(results))]
129
    if not inputs:
130
        print(f"No result JSONL files found. Pass files explicitly or populate {results}.")
131
        return 2
132
133
    checks: list[dict[str, Any]] = []
134
    checks.append(run_publish_gate(inputs, out_dir))
135
    if not args.skip_stats:
136
        checks.append(run_benchmark_stats(inputs, out_dir, args.bootstrap_samples, args.confidence))
137
    if not args.skip_opportunities:
138
        checks.append(run_opportunities(results, inputs, out_dir))
139
140
    manifest = {
141
        "generated_at": datetime.now(timezone.utc).isoformat(),
142
        "results_dir": str(results),
143
        "inputs": [str(path) for path in inputs],
144
        "out_dir": str(out_dir),
145
        "checks": checks,
146
        "ready": all(check["exit_code"] == 0 for check in checks),
147
    }
148
    manifest_path = out_dir / "manifest.json"
149
    manifest_path.write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n")
150
151
    print(f"Readiness bundle: {out_dir}")
152
    print(f"Manifest: {manifest_path}")
153
    for check in checks:
154
        status = "PASS" if check["exit_code"] == 0 else "FAIL"
155
        print(f"{status} {check['name']}: {check.get('path')}")
156
    return 0 if manifest["ready"] else 1
157
158
159
if __name__ == "__main__":
160
    raise SystemExit(main())