Download evals/postmortem/run.py from SaylorTwift/hermes-agent: direct link, hf CLI and curl.
- Browser
- Download file 4.67 kB
-
https://huggingface.co/SaylorTwift/hermes-agent/resolve/main/evals/postmortem/run.py
- Command line
-
hf download hf://SaylorTwift/hermes-agent/evals/postmortem/run.py
-
curl -L -o run.py https://huggingface.co/SaylorTwift/hermes-agent/resolve/main/evals/postmortem/run.py
4.67 kB
| #!/usr/bin/env python3 | |
| """Run the post-mortem harness against one or two checkouts and print a comparison table. | |
| python -m evals.postmortem.run --repo /path/to/checkout # one ref: pass/fail per probe | |
| python -m evals.postmortem.run --repo A --compare B # two refs: side by side | |
| python -m evals.postmortem.run --repo A --live # also the probes that spend money | |
| Each probe is a standalone script run in a fresh interpreter with the target checkout on sys.path and a | |
| temp HERMES_HOME (probes that need real credentials say so and are only run with --live). A probe | |
| "passes" when its process exits 0 AND its stdout contains the expected marker documented in | |
| PROBES below; the marker is the behaviour the corresponding PR fixed. Run the forensics lanes | |
| separately (they need a state.db copy): see forensics/README section in ../README.md. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import os | |
| import subprocess | |
| import sys | |
| import tempfile | |
| from pathlib import Path | |
| HERE = Path(__file__).resolve().parent | |
| # (script, args-template, expected stdout substring, live?, PR) | |
| # Two probes pass on main as well: scanner_bypass_probe (main blocked the witness too, as "malformed") and | |
| # notice_delivery_probe (main has no interim notice to mis-deliver). They guard against regressing INTO the | |
| # round-1 defects, which is why they are here. | |
| PROBES = [ | |
| ("live_ab/hardline_scanner_matrix.py", ["{repo}"], "ALL OK", False, "#103492"), | |
| ("review_probes/scanner_bypass_probe.py", ["{repo}"], '"hardline": true', False, "#103492"), | |
| ("live_ab/subagent_context_cap.py", ["{repo}"], "trigger=200,000", False, "#103513"), | |
| ("live_ab/batch_failure_notice.py", ["{repo}"], "TASK_FAILURE_NOTICE", False, "#103549"), | |
| ("review_probes/notice_delivery_probe.py", ["{repo}"], "PROBE_COMPLETE", False, "#103549"), | |
| ("review_probes/cache_estimator_probe.py", ["{repo}"], '"preflight_should_compress": true', False, "#103476"), | |
| ("review_probes/rewrite_hint_probe.py", ["{repo}"], "remote_fifo", False, "#103551"), | |
| ("live_ab/auth_stampede.py", ["{repo}", "12"], "server_401=0", False, "#103526"), | |
| ("review_probes/credential_identity_probe.py", ["{repo}", "pr"], '"after_sub": "account-A"', False, "#103526"), | |
| # live (real provider calls, cents each) | |
| ("live_ab/goal_judge_wait.py", ["{repo}", "3"], "('wait', ", True, "#103534"), | |
| ("live_ab/cache_prefix_wire.py", ["{repo}", "B"], "", True, "#103476"), | |
| ] | |
| def run_probe(script: str, args: list[str], repo: str, timeout: int = 240) -> tuple[int, str]: | |
| env = dict(os.environ) | |
| env.setdefault("HERMES_HOME", tempfile.mkdtemp(prefix="pm-probe-")) | |
| env["PYTHONPATH"] = repo + os.pathsep + env.get("PYTHONPATH", "") | |
| cmd = [sys.executable, str(HERE / script), *[a.format(repo=repo) for a in args]] | |
| try: | |
| p = subprocess.run(cmd, cwd=repo, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout, env=env) | |
| return p.returncode, (p.stdout + "\n" + p.stderr) | |
| except subprocess.TimeoutExpired: | |
| return 124, "TIMEOUT" | |
| def main(argv=None) -> int: | |
| ap = argparse.ArgumentParser(description=(__doc__ or "").split("\n\n")[0]) | |
| ap.add_argument("--repo", required=True) | |
| ap.add_argument("--compare", default=None, help="second checkout to run side by side (e.g. main vs branch)") | |
| ap.add_argument("--live", action="store_true", help="also run probes that make real provider calls") | |
| ap.add_argument("--only", default=None, help="substring filter on script path or PR number") | |
| a = ap.parse_args(argv) | |
| repos = [a.repo] + ([a.compare] if a.compare else []) | |
| rows = [] | |
| for script, args, marker, live, pr in PROBES: | |
| if live and not a.live: | |
| continue | |
| if a.only and a.only not in script and a.only not in pr: | |
| continue | |
| cells = [] | |
| for repo in repos: | |
| rc, out = run_probe(script, args, os.path.abspath(repo)) | |
| ok = rc == 0 and (marker in out if marker else True) | |
| cells.append("PASS" if ok else f"FAIL(rc={rc})") | |
| rows.append((pr, script, *cells)) | |
| width = max(len(r[1]) for r in rows) if rows else 20 | |
| head = f"{'PR':<9} {'probe':<{width}} " + " ".join(f"{os.path.basename(os.path.normpath(r)):<14}" for r in repos) | |
| print(head); print("-" * len(head)) | |
| for r in rows: | |
| print(f"{r[0]:<9} {r[1]:<{width}} " + " ".join(f"{c:<14}" for c in r[2:])) | |
| failed = any("FAIL" in c for r in rows for c in r[2 + (1 if a.compare else 0):]) # only the LAST column gates | |
| return 1 if failed else 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |