Files
wehub-resource-sync 4b6817381b
Benchmark image — build + push to ECR (any adapter) / build + push (push) Waiting to run
CI / quality (ubuntu-latest) (push) Waiting to run
CI / test (tools-runtime) (push) Waiting to run
CI / test (e2e-general) (push) Waiting to run
CI / test (cli-runtime) (push) Waiting to run
CI / test (e2e-provider-and-openclaw) (push) Waiting to run
CI / test (integrations-and-misc) (push) Waiting to run
CI / coverage-report (push) Blocked by required conditions
CI / test-kubernetes (push) Waiting to run
CI / should-run-thorough (push) Waiting to run
CI / test-thorough (cloudwatch-demo) (push) Blocked by required conditions
CI / test-thorough (flink-ecs) (push) Blocked by required conditions
CI / test-thorough (upstream-lambda) (push) Blocked by required conditions
CI / test-thorough (prefect-ecs-fargate) (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Blocked by required conditions
Release / publish-release (push) Blocked by required conditions
Release / publish-main-release (push) Blocked by required conditions
Release / prepare (push) Waiting to run
Release / verify (push) Blocked by required conditions
Release / build-python-dist (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Blocked by required conditions
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Waiting to run
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

846 lines
35 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Benchmark orchestrator — wires Config + Adapter + IntegrityGuard + CostTracker.
Runs the (case × mode × llm × run) grid serially for v1; parallel workers
land in v1.1 once the serial path is verified end-to-end.
Two entry points:
- ``BenchmarkRunner.run()`` — production. Enforces all integrity gates,
refuses to start without pre-registration + validity metrics + seeded
selection; refuses to emit a report without per-stratum breakdown +
negative-results + COI.
- ``BenchmarkRunner.run_without_integrity()`` — DEVELOPMENT ONLY. Skips
integrity gates so the rest of the wiring can be smoke-tested before
Phase C (validity metrics) and Phase D (seen/unseen tagging) ship.
Stamps results with ``dev_mode=True`` so they can't be silently
promoted to a real report.
opensre+LLM mode wires opensre's ``run_investigation`` against the adapter's
integrations + investigation agent. ``llm_alone`` mode (the control arm) wires
the same per-case tool surface but the adapter's baseline agent class, so the
contrast isolates opensre's policy delta on a fixed model. The runner refuses
``modes=["llm_alone"]`` only when the adapter returns ``None`` from
``baseline_agent_class`` (see ``_run_inner``).
llm_dispatch pins the model per cell: the dispatcher activates each LLM, sets
the provider env, resets opensre's client singletons, and verifies the
resolved snapshot against ``config.model_versions``. ``RunResult.model_version``
records what opensre actually resolved to, not what the YAML requested.
"""
from __future__ import annotations
import hashlib
import json
import os
import re
import subprocess
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from dataclasses import dataclass, field
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, cast
from core.llm.shared.llm_retry import LLMCreditExhaustedError
from tests.benchmarks._framework.adapters import (
BenchmarkAdapter,
BenchmarkCase,
CaseFilters,
CaseScore,
Mode,
RunContext,
RunResult,
)
from tests.benchmarks._framework.config import BenchmarkConfig
from tests.benchmarks._framework.cost import CostBudgetExceeded, CostTracker, UnknownModel
from tests.benchmarks._framework.integrity import (
BenchmarkReport,
IntegrityGuard,
IntegrityViolation,
make_baseline_report,
)
from tests.benchmarks._framework.llm_dispatch import (
LLMDispatcher,
LLMSpec,
MissingAPIKey,
ModelVersionMismatch,
UnknownLLM,
)
from tests.benchmarks._framework.provenance import capture_provenance
from tests.benchmarks._framework.reporting import render_report_dir
# --------------------------------------------------------------------------- #
# Internal types #
# --------------------------------------------------------------------------- #
@dataclass
class _CellResult:
"""One scenario × mode × llm × run cell with run + score + on-disk path."""
case: BenchmarkCase
mode: Mode
llm: str
run_index: int
run: RunResult
score: CaseScore
artifact_path: Path
@dataclass
class RunOutcome:
"""What ``run()`` returns: the report + the cell-by-cell results."""
report: BenchmarkReport
cells: list[_CellResult] = field(default_factory=list)
aborted: bool = False
abort_reason: str | None = None
# --------------------------------------------------------------------------- #
# BenchmarkRunner #
# --------------------------------------------------------------------------- #
class BenchmarkRunner:
"""Drives a single benchmark run end-to-end.
Supports: serial or worker-pool execution; both ``opensre+llm`` and the
``llm_alone`` control arm (when the adapter provides a baseline agent);
per-cell LLM dispatch with version pinning; and per-stratum reporting
(all / seen-shape / unseen-shape / held-out / optimize / consistency-
selected). Headline aggregation (mean + scenario-clustered CI) lives in
``reporting.py``; this runner stores per-stratum medians.
"""
def __init__(
self,
config: BenchmarkConfig,
adapter: BenchmarkAdapter,
integrity_guard: IntegrityGuard | None = None,
cost_tracker: CostTracker | None = None,
dispatcher: LLMDispatcher | None = None,
config_path: Path | None = None,
) -> None:
self.config = config
self.adapter = adapter
self.integrity = integrity_guard or IntegrityGuard()
self.cost = cost_tracker or CostTracker(budget_usd=config.cost_budget_usd)
self.dispatcher = dispatcher or LLMDispatcher()
self._opensre_sha = _git_sha()
# Where the YAML was loaded from. Threaded into capture_provenance so
# the run dir's provenance.json inlines the config content + sha256.
# None when the runner is constructed inline (e.g. unit tests).
self._config_path = config_path
# ----------------------------------------------------------------------- #
# Public API #
# ----------------------------------------------------------------------- #
def run(self) -> RunOutcome:
"""Production entry point: enforces all integrity gates."""
self.integrity.pre_flight(self.config, self.adapter)
# Reject promotable runs whose opensre_sha is not a verifiable git
# SHA. Two failure modes the gate must catch:
#
# 1. ``(no-git)`` / ``(unknown)`` / empty — the 2026-06-11 partial
# full-N's failure mode. Fargate container had no .git directory,
# OPENSRE_SHA was not stamped, the runner reported (no-git), and
# no integrity check rejected it.
# 2. Arbitrary non-SHA strings like ``hotfix-june`` or ``v1.0``.
# Possible when a manual image build sets OPENSRE_SHA from a
# user-supplied tag instead of the real commit SHA. Such values
# pass the ``not (no-git)`` check but are unverifiable — you
# cannot ``git checkout hotfix-june`` and reproduce the run.
#
# A valid git SHA is 7-40 lowercase hex characters (short or full
# form). Anything else is rejected. ``run_without_integrity`` is
# the explicit escape hatch for exploratory runs.
_validate_promotable_sha(self._opensre_sha)
return self._run_inner(dev_mode=False)
def run_without_integrity(self) -> RunOutcome:
"""DEVELOPMENT ONLY: skip integrity gates so the wiring can be tested
before Phase C (validity metrics) and Phase D (seen/unseen tagging).
Produced reports are stamped ``dev_mode=True`` (via run_id prefix)
so they cannot be silently promoted to publication-ready artifacts.
"""
print(
" ⚠ run_without_integrity() — INTEGRITY GATES SKIPPED — "
"results are NOT publication-grade"
)
return self._run_inner(dev_mode=True)
# ----------------------------------------------------------------------- #
# Internals #
# ----------------------------------------------------------------------- #
def _run_inner(self, *, dev_mode: bool) -> RunOutcome:
# Refuse baseline modes if the adapter declines — keeps the runner
# generic over adapters that don't yet ship a matched control arm.
# Both checks are pre-flight so an unsupported mode fails before any
# cell runs and burns tokens.
if "llm_alone" in self.config.modes and self.adapter.baseline_agent_class() is None:
raise NotImplementedError(
f"Adapter {self.adapter.name!r} does not implement an llm_alone "
"control arm (baseline_agent_class returned None). Run with "
"modes=['opensre+llm'] only, or extend the adapter."
)
if (
"llm_alone_pure" in self.config.modes
and self.adapter.pure_baseline_agent_class() is None
):
raise NotImplementedError(
f"Adapter {self.adapter.name!r} does not implement a pure baseline "
"(pure_baseline_agent_class returned None). Drop llm_alone_pure "
"from modes, or extend the adapter with a prompt-stripped agent."
)
# Pre-flight: verify every LLM in config is registered AND that its
# pinned model_version matches the spec. Fail-fast before any cell runs.
# Raises UnknownLLM or ModelVersionMismatch; caller surfaces as failure.
self._verify_llm_specs()
run_id = self._build_run_id(dev_mode=dev_mode)
output_dir = self.config.output_dir / run_id
cases_dir = output_dir / "cases"
cases_dir.mkdir(parents=True, exist_ok=True)
started_at = datetime.now(UTC).isoformat()
cells: list[_CellResult] = []
aborted = False
abort_reason: str | None = None
# Capture provenance before any LLM call so reviewers can audit
# exactly what code + config + env produced the report. Failure is
# FATAL — a run without provenance has no reproducibility story.
provenance = capture_provenance(
config=self.config,
adapter=self.adapter,
run_id=run_id,
started_at=started_at,
config_path=self._config_path,
)
(output_dir / "provenance.json").write_text(
json.dumps(provenance, ensure_ascii=False, indent=2) + "\n",
encoding="utf-8",
)
print(f" ✓ wrote {output_dir / 'provenance.json'}")
cases = list(
self.adapter.load_cases(
CaseFilters(
systems=self.config.filters.systems,
fault_categories=self.config.filters.fault_categories,
difficulty=self.config.filters.difficulty,
seen_shape=self.config.filters.seen_shape,
case_ids=self.config.filters.case_ids,
limit=self.config.filters.limit,
seed=self.config.seed,
)
)
)
print(f" loaded {len(cases)} case(s)")
# Register the cost-accounting hook so every successful LLM call
# inside opensre's agent feeds CostTracker. Cleared in finally so
# the hook doesn't leak into other test code that imports llm_client.
from core.llm.shared.usage import set_usage_hook
set_usage_hook(self.cost.add)
# Serialize across LLMs (opensre's LLM client is a module-level
# singleton — swapping mid-flight would race). Parallel within a
# single LLM activation.
try:
for llm in self.config.llms:
print(f" ▶ activating LLM: {llm}")
with self.dispatcher.activate(llm) as spec:
llm_cell_specs: list[tuple[BenchmarkCase, Mode, str, int]] = [
(case, cast(Mode, mode), llm, run_index)
for case in cases
for mode in self.config.modes
for run_index in range(self.config.runs_per_case)
]
cells.extend(
self._execute_llm_batch(
specs=llm_cell_specs,
spec=spec,
cases_dir=cases_dir,
)
)
except CostBudgetExceeded as exc:
aborted = True
abort_reason = str(exc)
print(f" ✗ aborted: {abort_reason}")
except (UnknownLLM, ModelVersionMismatch, MissingAPIKey) as exc:
aborted = True
abort_reason = f"LLM dispatch failed: {exc}"
print(f" ✗ aborted: {abort_reason}")
finally:
set_usage_hook(None)
ended_at = datetime.now(UTC).isoformat()
# Build the report (per-stratum aggregation)
per_stratum = _aggregate_per_stratum(
cells, self.adapter.metric_schema().all_metrics(), adapter=self.adapter
)
negative = _build_negative_results(cells, self.adapter)
config_hash = _hash_config(self.config)
report = make_baseline_report(
run_id=run_id,
config_hash=config_hash,
started_at=started_at,
ended_at=ended_at,
per_stratum=per_stratum,
reported_metrics=self.adapter.metric_schema().all_metrics(),
raw_artifacts_dir=cases_dir,
pre_registration_path=self.config.pre_registration_path or Path("dev-mode-no-prereg"),
negative_results=negative or "(no losses or ties recorded in this run)",
)
# Persist a JSON sidecar to output_dir/report.json regardless of validation
(output_dir / "report.json").write_text(
json.dumps(_report_to_dict(report, self.cost), ensure_ascii=False, indent=2) + "\n",
encoding="utf-8",
)
# Auto-render markdown + HTML (or whichever formats the config requested).
# Failure here is non-fatal — JSON is the source of truth; the
# human-readable views can be regenerated via `bench report` later.
render_formats = [f for f in self.config.report_formats if f != "json"]
if render_formats:
try:
rendered = render_report_dir(output_dir, formats=render_formats)
for fmt, path in rendered.items():
print(f" ✓ rendered {fmt}: {path}")
except Exception as exc:
print(f" ⚠ report rendering failed (JSON still written): {exc}")
# Production runs gate emission on report_validation; dev runs skip
if not dev_mode:
self.integrity.report_validation(report, self.adapter)
return RunOutcome(report=report, cells=cells, aborted=aborted, abort_reason=abort_reason)
def _verify_llm_specs(self) -> None:
"""Pre-flight: confirm every LLM in config has a registered spec and
the config's pinned ``model_versions[<llm>]`` matches.
Raises UnknownLLM or ModelVersionMismatch from llm_dispatch — caught
by _run_inner and surfaced as ``abort_reason``.
"""
for llm in self.config.llms:
self.dispatcher.spec(llm) # raises UnknownLLM
configured = self.config.model_versions.get(llm, "")
self.dispatcher.verify_model_version(llm, configured)
def _execute_llm_batch(
self,
*,
specs: list[tuple[BenchmarkCase, Mode, str, int]],
spec: LLMSpec,
cases_dir: Path,
) -> list[_CellResult]:
"""Run a batch of cells under one already-activated LLM dispatcher.
Within an LLM, parallel via ThreadPoolExecutor is safe (singleton
is stable for the duration of the activation context).
"""
results: list[_CellResult] = []
if self.config.workers <= 1:
for case, mode_cast, llm, run_index in specs:
results.append(
self._run_one_cell(
case=case,
mode=mode_cast,
llm=llm,
spec=spec,
run_index=run_index,
cases_dir=cases_dir,
)
)
return results
with ThreadPoolExecutor(max_workers=self.config.workers) as executor:
future_to_spec = {
executor.submit(
self._run_one_cell,
case=case,
mode=mode_cast,
llm=llm,
spec=spec,
run_index=run_index,
cases_dir=cases_dir,
): (case, mode_cast, llm, run_index)
for case, mode_cast, llm, run_index in specs
}
for future in as_completed(future_to_spec):
try:
results.append(future.result())
except (CostBudgetExceeded, LLMCreditExhaustedError):
# Both are run-fatal: cost budget halts on operator-set
# cap; credit exhaustion halts because no retry can
# recover a dead provider account. Cancel pending
# futures so we don't burn time on cells destined to
# fail the same way.
for f in future_to_spec:
f.cancel()
raise
return results
def _run_one_cell(
self,
*,
case: BenchmarkCase,
mode: Mode,
llm: str,
spec: LLMSpec,
run_index: int,
cases_dir: Path,
) -> _CellResult:
"""Execute one (case × mode × llm × run) cell."""
# Late import — keeps the rest of the framework importable without
# opensre's full dep tree loaded.
from tools.investigation.capability import run_investigation
alert = self.adapter.build_alert(case)
# Mode dispatch: opensre+llm uses the adapter's full integration setup
# + investigation agent; llm_alone uses the (typically identical) baseline
# tool surface + a different agent class. Both go through the same
# run_investigation entry point so the rest of the pipeline (format,
# score, artifact write) is mode-agnostic.
if mode == "llm_alone":
integrations = self.adapter.build_baseline_tools(case)
agent_class = self.adapter.baseline_agent_class()
elif mode == "llm_alone_pure":
# Same tool surface as the other baseline (build_baseline_tools);
# only the agent class differs — minimal system prompt instead of
# opensre's full planner/verifier prompt.
integrations = self.adapter.build_baseline_tools(case)
agent_class = self.adapter.pure_baseline_agent_class()
else:
integrations = self.adapter.build_opensre_integrations(case)
agent_class = self.adapter.investigation_agent_class()
started = datetime.now(UTC)
t0 = time.monotonic()
ok = True
error: str | None = None
final_state_dict: dict[str, Any] = {}
try:
final_state = run_investigation(
alert.raw,
resolved_integrations=integrations,
agent_class=agent_class,
)
final_state_dict = dict(final_state)
except (CostBudgetExceeded, UnknownModel, LLMCreditExhaustedError):
# Run-fatal: propagate up to _execute_llm_batch / _run_inner so
# the run halts at the configured budget ceiling. Without this
# explicit re-raise, the broad `except Exception` below would
# silently record the breach as a per-cell failure and the run
# would continue past the cap.
#
# UnknownModel: pre-flight problem (model missing from pricing
# table) — must halt, not mask as cell failure.
#
# LLMCreditExhaustedError: provider billing/quota exhausted
# (e.g. OpenAI insufficient_quota, Anthropic credit-balance-too-low).
# Retries can't help — operator must top up balance. Run #2 of the
# June-3 bench burned 1h42m wall-clock on this before the halt
# path existed; halting on first occurrence prevents recurrence.
raise
except Exception as exc:
ok = False
error = f"{type(exc).__name__}: {exc}"
latency_ms = int((time.monotonic() - t0) * 1000)
ended = datetime.now(UTC)
# Cost tracking happens out-of-band: core/llm/llm_client._emit_usage
# fires self.cost.add for every successful LLM call the agent makes,
# so totals in report.json reflect real spend. Per-cell tokens/cost
# below stay at 0 (delta capture is a follow-up — would need a
# before/after snapshot bracketing run_investigation, complicated by
# ThreadPoolExecutor shared-state).
run = RunResult(
case_id=case.case_id,
mode=mode,
llm=llm,
# Pinned via llm_dispatch — what opensre's LLM client actually resolved to,
# not what the user wrote in YAML (those must match by pre-flight check).
model_version=spec.reasoning_model,
opensre_sha=self._opensre_sha,
started_at=started.isoformat(),
ended_at=ended.isoformat(),
ok=ok,
error=error,
final_diagnosis={
"stage": final_state_dict.get("root_cause_category") or "",
"component": "",
"root_cause": final_state_dict.get("root_cause") or "",
"report": final_state_dict.get("report") or "",
},
evidence_entries=list(cast(list[Any], final_state_dict.get("evidence_entries") or [])),
tokens_in=0, # llm_dispatch fills this
tokens_out=0,
cost_usd=0.0,
latency_ms=latency_ms,
)
# Adapter hook: optionally enrich run.final_diagnosis (e.g.,
# CloudOpsBench emits paper-format top_3_predictions here so the
# scorer doesn't have to inference from free-text RCA). Default
# ABC implementation is a no-op for adapters that don't need it.
run = self.adapter.format_final_answer(case, run, spec)
score = self.adapter.score_case(case, run, RunContext(integrations=integrations))
# Per-cell artifact
artifact_path = (
cases_dir / f"{case.case_id.replace('/', '_')}__{mode}__{llm}__{run_index}.json"
)
artifact_path.write_text(
json.dumps(
_cell_to_dict(case, run, score),
ensure_ascii=False,
indent=2,
)
+ "\n",
encoding="utf-8",
)
inv_a1 = score.metrics.get("investigation_a1")
inv_suffix = f" inv_a1={inv_a1:.2f}" if inv_a1 is not None else ""
print(
f" {case.case_id} [{mode} · {llm} · run {run_index}] "
f"a1={score.metrics.get('a1', 0):.2f}{inv_suffix} "
f"steps={score.metrics.get('steps', 0):.0f} "
f"{latency_ms}ms"
)
return _CellResult(
case=case,
mode=mode,
llm=llm,
run_index=run_index,
run=run,
score=score,
artifact_path=artifact_path,
)
# ----------------------------------------------------------------------- #
# Helpers #
# ----------------------------------------------------------------------- #
def _build_run_id(self, *, dev_mode: bool) -> str:
ts = datetime.now(UTC).strftime("%Y-%m-%dT%H-%M-%SZ")
prefix = "dev-" if dev_mode else ""
return f"{prefix}{ts}_{self.adapter.name}"
# --------------------------------------------------------------------------- #
# Aggregation + serialization helpers #
# --------------------------------------------------------------------------- #
def _aggregate_per_stratum(
cells: list[_CellResult],
metrics: list[str],
*,
adapter: BenchmarkAdapter | None = None,
) -> dict[str, dict[str, dict[str, float]]]:
"""Aggregate cell metrics into the per_stratum shape IntegrityGuard expects.
Shape: {stratum: {f"{mode}/{llm}": {metric: median_value}}}
Strata populated:
- ``all`` — every cell, median across runs
- ``seen-shape`` / ``unseen-shape`` — Phase D tag from
``BenchmarkCase.seen_shape``; mid-shape cells appear only in ``all``
- ``held-out`` / ``optimize`` — generalization-gate split from
``BenchmarkCase.metadata["is_held_out"]``; required by integrity
Mechanism 8 so reports can compute ``held_out_lift / optimize_lift``
per the pre-registration's ``generalization_gate`` clause
- ``consistency-selected`` — one run per (case, mode, llm)
group, picked by ``adapter.select_best_run``. Emitted only when
the adapter overrides the hook AND at least one group returns a
non-None index. Lets reports show median + selected side-by-side
without mutating the standard ``all`` view.
``adapter`` is optional so existing callers (tests, downstream
framework integrators) keep working with median-only aggregation;
passing the adapter enables the selected stratum.
"""
by_stratum_mode_llm: dict[str, dict[str, dict[str, list[float]]]] = {"all": {}}
# Group cells by (case_id, mode, llm) so the adapter's selector can
# see all seeds of one scenario together. dict preserves insertion order
# so the index it returns is stable w.r.t. the runs list.
by_scenario: dict[tuple[str, str, str], list[_CellResult]] = {}
for cell in cells:
key = f"{cell.mode}/{cell.llm}"
def append_to(stratum: str, _cell: _CellResult = cell, _key: str = key) -> None:
bucket = by_stratum_mode_llm.setdefault(stratum, {}).setdefault(
_key, {m: [] for m in metrics}
)
for m in metrics:
bucket[m].append(_cell.score.metrics.get(m, 0.0))
append_to("all")
if cell.case.seen_shape is True:
append_to("seen-shape")
elif cell.case.seen_shape is False:
append_to("unseen-shape")
held_out = cell.case.metadata.get("is_held_out") if cell.case.metadata else None
if held_out is True:
append_to("held-out")
elif held_out is False:
append_to("optimize")
by_scenario.setdefault((cell.case.case_id, cell.mode, cell.llm), []).append(cell)
# Consistency selection: ask the adapter to pick the canonical run per
# scenario. A None return for any group means "no pick" — that group's
# cells are skipped in the selected stratum, the others still count.
if adapter is not None:
for group in by_scenario.values():
if not group:
continue
try:
picked = adapter.select_best_run(group[0].case, [(c.run, c.score) for c in group])
except Exception as exc:
# Selector errors must not abort the report — fall back to
# median-only. Log so the failure surfaces in the run log.
print(f" ⚠ select_best_run raised for {group[0].case.case_id}: {exc}")
continue
if picked is None or not (0 <= picked < len(group)):
continue
chosen = group[picked]
key = f"{chosen.mode}/{chosen.llm}"
bucket = by_stratum_mode_llm.setdefault("consistency-selected", {}).setdefault(
key, {m: [] for m in metrics}
)
for m in metrics:
bucket[m].append(chosen.score.metrics.get(m, 0.0))
return {
stratum: {
mode_llm: {m: _median(values) for m, values in metric_bucket.items()}
for mode_llm, metric_bucket in by_mode_llm.items()
}
for stratum, by_mode_llm in by_stratum_mode_llm.items()
}
def _median(values: list[float]) -> float:
if not values:
return 0.0
s = sorted(values)
n = len(s)
mid = n // 2
if n % 2 == 1:
return s[mid]
return (s[mid - 1] + s[mid]) / 2.0
def _build_negative_results(cells: list[_CellResult], adapter: BenchmarkAdapter) -> str:
"""Build the negative-results section: cases where a1 == 0.
Honest reporting per integrity Mechanism 9.
"""
losses = [c for c in cells if c.score.metrics.get("a1", 0.0) == 0.0]
if not losses:
return ""
lines = [
f"opensre lost or tied on {len(losses)} of {len(cells)} cell(s) (adapter={adapter.name}):"
]
for c in losses[:50]: # cap output
lines.append(
f" - {c.case.case_id} mode={c.mode} llm={c.llm} run={c.run_index} "
f"a1=0.00 artifact={c.artifact_path.name}"
)
if len(losses) > 50:
lines.append(f" ... and {len(losses) - 50} more (see report.json for full list)")
return "\n".join(lines)
def _hash_config(config: BenchmarkConfig) -> str:
"""Stable hash of the config so two runs of the same config can be diffed."""
serialized = json.dumps(config.model_dump(mode="json"), sort_keys=True, default=str)
return hashlib.sha256(serialized.encode()).hexdigest()[:16]
_SHA_SHAPE = re.compile(r"^[0-9a-f]{7,40}$")
def _validate_promotable_sha(sha: str | None) -> None:
"""Raise IntegrityViolation if ``sha`` is not a verifiable git SHA.
A real git SHA is 7-40 hex characters (lowercase). Anything else —
``(no-git)``, ``(unknown)``, empty, or arbitrary tags like
``hotfix-june`` / ``v1.0`` — cannot be checked out and therefore
breaks the reproducibility contract the promotable cycle depends on.
"""
sha_str = (sha or "").strip()
if sha_str and _SHA_SHAPE.fullmatch(sha_str):
return
raise IntegrityViolation(
[
f"opensre_sha={sha!r} is not a verifiable git SHA (expected 7-40 "
f"lowercase hex characters). The promotable run path requires a "
f"real commit SHA so the artifacts can be reproduced. Resolution "
f"sources, in order: the OPENSRE_SHA env var stamped by the bench "
f"image build workflow (.github/workflows/benchmark-image.yml — "
f"set from github.sha, NOT the user-supplied image tag), or "
f"git rev-parse from a checked-out source tree. Use "
f"run_without_integrity() for exploratory runs that don't need "
f"a verifiable SHA."
]
)
def _git_sha() -> str:
"""opensre git SHA for the running code. Used in RunResult for reproducibility.
Resolution order:
1. ``OPENSRE_SHA`` environment variable — set by the bench image build
workflow (.github/workflows/benchmark-image.yml) so Fargate runs,
which have no ``.git`` directory, can still stamp the real SHA.
2. ``git rev-parse HEAD`` — used by local developer runs.
3. ``(no-git)`` — fallback when neither is available.
The env-var path is required because the bench image is built from a
checked-out source tree but the resulting container ships only the
runtime code (no .git). Without OPENSRE_SHA, every Fargate run stamps
``(no-git)``, which the integrity gate then rejects for promotable
cycles. The build workflow must export OPENSRE_SHA at image-build time
(e.g. ``ENV OPENSRE_SHA=${GITHUB_SHA::7}`` in the Dockerfile, or pass
as an ECS container override).
"""
env_sha = os.environ.get("OPENSRE_SHA", "").strip()
if env_sha:
return env_sha
try:
result = subprocess.run(
["git", "rev-parse", "--short", "HEAD"],
capture_output=True,
text=True,
check=False,
cwd=Path(__file__).parent,
)
sha = result.stdout.strip()
if not sha:
return "(unknown)"
# Check for uncommitted changes
dirty = subprocess.run(
["git", "status", "--porcelain"],
capture_output=True,
text=True,
check=False,
cwd=Path(__file__).parent,
)
suffix = "-dirty" if dirty.stdout.strip() else ""
return f"{sha}{suffix}"
except (FileNotFoundError, OSError):
return "(no-git)"
_EVIDENCE_OUTPUT_TRUNCATE_CHARS = 2000
def _truncate_evidence_entries(entries: list[Any]) -> list[Any]:
"""Truncate the verbose ``data`` payload on each entry for case-file size.
Keeps ``tool_name`` + ``tool_args`` verbatim — those are small and
structural. Truncates ``data.output`` / ``data.content`` to the first
``_EVIDENCE_OUTPUT_TRUNCATE_CHARS`` characters so a B-track guard or
post-hoc analyzer can still detect failure-status tokens (CrashLoop,
ImagePull, etc.) without bloating the case JSON at full-grid scale.
"""
truncated: list[Any] = []
for entry in entries:
if not isinstance(entry, dict):
truncated.append(entry)
continue
kept = dict(entry)
data = kept.get("data")
if isinstance(data, dict):
shrunk = dict(data)
for key in ("output", "content", "text", "message"):
value = shrunk.get(key)
if isinstance(value, str) and len(value) > _EVIDENCE_OUTPUT_TRUNCATE_CHARS:
shrunk[key] = value[:_EVIDENCE_OUTPUT_TRUNCATE_CHARS] + "...[truncated]"
kept["data"] = shrunk
elif isinstance(data, str) and len(data) > _EVIDENCE_OUTPUT_TRUNCATE_CHARS:
kept["data"] = data[:_EVIDENCE_OUTPUT_TRUNCATE_CHARS] + "...[truncated]"
truncated.append(kept)
return truncated
def _cell_to_dict(case: BenchmarkCase, run: RunResult, score: CaseScore) -> dict[str, Any]:
"""Serializable shape for per-case artifact JSON."""
return {
"case": {
"case_id": case.case_id,
"benchmark_name": case.benchmark_name,
"metadata": case.metadata,
"seen_shape": case.seen_shape,
},
"run": {
"mode": run.mode,
"llm": run.llm,
"model_version": run.model_version,
"opensre_sha": run.opensre_sha,
"started_at": run.started_at,
"ended_at": run.ended_at,
"ok": run.ok,
"error": run.error,
"final_diagnosis": run.final_diagnosis,
"evidence_entries_count": len(run.evidence_entries),
# Truncated entries (verbose ``data`` payload capped) for post-hoc
# analysis of which evidence the agent saw. The B-track false-healthy
# guard reads this at runtime from the full list; the truncated copy
# is the disk-side audit trail.
"evidence_entries": _truncate_evidence_entries(run.evidence_entries),
"tokens_in": run.tokens_in,
"tokens_out": run.tokens_out,
"cost_usd": run.cost_usd,
"latency_ms": run.latency_ms,
},
"score": {
"metrics": score.metrics,
"failure_reason": score.failure_reason,
},
}
def _report_to_dict(report: BenchmarkReport, cost: CostTracker) -> dict[str, Any]:
"""Serializable shape for report.json."""
return {
"run_id": report.run_id,
"config_hash": report.config_hash,
"started_at": report.started_at,
"ended_at": report.ended_at,
"per_stratum": report.per_stratum,
"reported_metrics": report.reported_metrics,
"negative_results": report.negative_results,
"coi_disclosure": report.coi_disclosure,
"raw_artifacts_dir": str(report.raw_artifacts_dir) if report.raw_artifacts_dir else None,
"pre_registration_path": str(report.pre_registration_path)
if report.pre_registration_path
else None,
"cost": cost.summary(),
"opensre_sha": _git_sha(),
"host": {"user": os.environ.get("USER", ""), "cwd": str(Path.cwd())},
}