| 1 | """Adversarial saved-baseline comparisons and claim eligibility controls."""
|
| 2 | from dataclasses import replace
|
| 3 | import contextlib
|
| 4 | import io
|
| 5 | import json
|
| 6 | from pathlib import Path
|
| 7 | import subprocess
|
| 8 | import sys
|
| 9 | import tempfile
|
| 10 | import unittest
|
| 11 | from unittest.mock import patch
|
| 12 |
|
| 13 | sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
|
| 14 | import benchmark_stats
|
| 15 | from oakbench.baseline_book import Target, book_json, cells_from_rows, load_baseline_book
|
| 16 | from oakbench.populations import comparison_identity
|
| 17 | from oakbench.scorecard import evaluate_targets
|
| 18 |
|
| 19 |
|
| 20 | def rows(subject="git", **overrides):
|
| 21 | result = []
|
| 22 | for index in range(30):
|
| 23 | row = dict(subject=subject, subject_kind="git" if subject == "git" else "oak",
|
| 24 | bench_id="campaign", run=index, lane="core", profile="standard",
|
| 25 | scenario="tiny", operation="status.clean", returncode=0,
|
| 26 | elapsed_ms=10.0 if subject == "git" else 1.0,
|
| 27 | benchmark_track="core-equivalent", command_semantics_version=1,
|
| 28 | fixture_version=1, scenario_version=1, runner_class="mac-arm",
|
| 29 | cache_state="warm", env_isolation_version="1", load_tier="idle",
|
| 30 | binary_sha256="git-sha" if subject == "git" else "oak-sha")
|
| 31 | row.update(overrides)
|
| 32 | result.append(row)
|
| 33 | return result
|
| 34 |
|
| 35 |
|
| 36 | TARGET = Target("t", "core", "standard", "tiny", "status.clean", "oak_local", "git",
|
| 37 | "elapsed_ms", "median", "ratio_at_most", .8, {})
|
| 38 |
|
| 39 |
|
| 40 | def aa_rows():
|
| 41 | """Interleaved Git A/A control (same Git, second subject name) for per-cell floors."""
|
| 42 | return [dict(row, subject="git_aa", subject_kind="git", elapsed_ms=10.0 + (0.05 if row["run"] % 2 else -0.05))
|
| 43 | for row in rows()]
|
| 44 |
|
| 45 |
|
| 46 | def baseline(source=None):
|
| 47 | return cells_from_rows((rows() + aa_rows()) if source is None else source, lane="core", metrics=("elapsed_ms",),
|
| 48 | statistics_names=("median",), noise_floor_pct=1.0, bootstrap_samples=20)[0]
|
| 49 |
|
| 50 |
|
| 51 | def evaluate(candidate=None, cell=None, mode="claim"):
|
| 52 | cell = baseline() if cell is None else cell
|
| 53 | return evaluate_targets(rows("oak_local") if candidate is None else candidate,
|
| 54 | [TARGET], {cell.key: cell}, mode=mode, bootstrap_samples=20)[0]
|
| 55 |
|
| 56 |
|
| 57 | class ClaimEligibilityTest(unittest.TestCase):
|
| 58 | def test_comparable_independent_trials_allow_different_vcs_binary_hashes(self):
|
| 59 | result = evaluate()
|
| 60 | self.assertEqual(result["verdict"], "GREEN")
|
| 61 | self.assertTrue(result["claim_eligible"])
|
| 62 |
|
| 63 | def test_saved_baseline_mismatch_is_invalid_even_in_diagnostic_mode(self):
|
| 64 | for field, value in [("runner_class", "linux"), ("fixture_version", 2),
|
| 65 | ("benchmark_track", "agent-default"), ("cache_state", "cold"),
|
| 66 | ("remote_transport", "network"), ("load_tier", "cpu50"),
|
| 67 | ("output_oracle_version", "different")]:
|
| 68 | with self.subTest(field=field):
|
| 69 | for mode in ("claim", "diagnostic"):
|
| 70 | result = evaluate(rows("oak_local", **{field: value}), mode=mode)
|
| 71 | self.assertEqual(result["verdict"], "INVALID")
|
| 72 | self.assertFalse(result["claim_eligible"])
|
| 73 |
|
| 74 | def test_missing_and_duplicate_trials_cannot_manufacture_precision(self):
|
| 75 | candidates = [rows("oak_local")[:1], rows("oak_local", run=0),
|
| 76 | rows("oak_local") + [rows("oak_local")[0]] * 1000]
|
| 77 | missing = rows("oak_local")
|
| 78 | del missing[0]["bench_id"]
|
| 79 | candidates.append(missing)
|
| 80 | for candidate in candidates:
|
| 81 | with self.subTest(n=len(candidate)):
|
| 82 | result = evaluate(candidate)
|
| 83 | self.assertEqual(result["verdict"], "AMBER")
|
| 84 | self.assertFalse(result["claim_eligible"])
|
| 85 |
|
| 86 | def test_unknown_baseline_evidence_cannot_be_public_green(self):
|
| 87 | for changes in ({"noise_floor_pct": None}, {"noise_floor_pct": float("nan")},
|
| 88 | {"noise_floor_pct": -1}, {"comparison_identity": None},
|
| 89 | {"comparison_identity": {}}, {"independent_n": 1},
|
| 90 | {"attempted_n": None}, {"failure_n": 1}, {"ci_low": None}):
|
| 91 | with self.subTest(changes=changes):
|
| 92 | result = evaluate(cell=replace(baseline(), **changes))
|
| 93 | self.assertNotEqual(result["verdict"], "GREEN")
|
| 94 | self.assertFalse(result["claim_eligible"])
|
| 95 |
|
| 96 | def test_low_or_unknown_confidence_cannot_qualify_as_claim_evidence(self):
|
| 97 | for confidence in (None, 0.5, float("nan"), 1.0):
|
| 98 | with self.subTest(baseline_confidence=confidence):
|
| 99 | self.assertFalse(evaluate(cell=replace(baseline(), confidence=confidence))["claim_eligible"])
|
| 100 | cell = cells_from_rows(rows(), lane="core", metrics=("elapsed_ms",), statistics_names=("median",),
|
| 101 | noise_floor_pct=1.0, bootstrap_samples=20, confidence=.5)[0]
|
| 102 | self.assertFalse(evaluate(cell=cell)["claim_eligible"])
|
| 103 | cell = baseline()
|
| 104 | result = evaluate_targets(rows("oak_local"), [TARGET], {cell.key: cell}, mode="claim",
|
| 105 | confidence=.5, bootstrap_samples=20)[0]
|
| 106 | self.assertEqual(result["verdict"], "AMBER")
|
| 107 | self.assertEqual(result["confidence"], .5)
|
| 108 | self.assertEqual(result["bootstrap_samples"], 20)
|
| 109 |
|
| 110 | def test_invalid_interval_arguments_rejected_before_scoring_or_building(self):
|
| 111 | for kwargs in ({"bootstrap_samples": 0}, {"bootstrap_samples": -1}, {"bootstrap_samples": True},
|
| 112 | {"bootstrap_samples": 1.5}, {"confidence": 0}, {"confidence": 1},
|
| 113 | {"confidence": float("nan")}, {"confidence": float("inf")}):
|
| 114 | with self.subTest(kwargs=kwargs):
|
| 115 | with self.assertRaises(ValueError):
|
| 116 | evaluate_targets([], [], {}, **kwargs)
|
| 117 | with self.assertRaises(ValueError):
|
| 118 | cells_from_rows([], lane="core", **kwargs)
|
| 119 |
|
| 120 | def test_uniformly_unknown_cache_cannot_be_claim_evidence(self):
|
| 121 | result = evaluate(rows("oak_local", cache_state="unknown"), baseline(rows(cache_state="unknown")))
|
| 122 | self.assertEqual(result["verdict"], "AMBER")
|
| 123 | self.assertIn("cache_state", " ".join(result["messages"]))
|
| 124 |
|
| 125 | def test_legacy_diagnostic_is_explicitly_not_claim_eligible(self):
|
| 126 | cell = replace(baseline(), comparison_identity=None, noise_floor_pct=None)
|
| 127 | result = evaluate(rows("oak_local")[:1], cell, mode="diagnostic")
|
| 128 | self.assertEqual(result["verdict"], "GREEN")
|
| 129 | self.assertFalse(result["claim_eligible"])
|
| 130 | self.assertIn("diagnostic only", " ".join(result["messages"]))
|
| 131 |
|
| 132 | def test_baseline_builder_preserves_failures_and_unmeasured_denominators(self):
|
| 133 | source = rows() + [dict(rows()[0], returncode=1), dict(rows()[0], elapsed_ms=None)]
|
| 134 | cell = baseline(source)
|
| 135 | self.assertEqual(cell.attempted_n, 32)
|
| 136 | self.assertEqual(cell.failure_n, 1)
|
| 137 | self.assertFalse(evaluate(cell=cell)["claim_eligible"])
|
| 138 |
|
| 139 | def test_global_operator_floor_is_not_claim_eligible_for_latency(self):
|
| 140 | # ADR-0011 / QA P1-5: no single floor for every cell on the claim path.
|
| 141 | cell = baseline(rows())
|
| 142 | self.assertEqual(cell.noise_floor_source, "operator_global")
|
| 143 | result = evaluate(cell=cell)
|
| 144 | self.assertFalse(result["claim_eligible"])
|
| 145 | self.assertTrue(any("per-cell A/A noise floor required" in m for m in result["claim_ineligibility_reasons"]))
|
| 146 | self.assertEqual(baseline().noise_floor_source, "per_cell_aa")
|
| 147 |
|
| 148 | def test_claim_verdicts_are_fdr_controlled_across_targets(self):
|
| 149 | from oakbench.scorecard import apply_claim_fdr
|
| 150 | results = [{"verdict": "GREEN", "p_value": 0.001, "claim_eligible": True},
|
| 151 | {"verdict": "GREEN", "p_value": 0.2, "claim_eligible": True},
|
| 152 | {"verdict": "AMBER", "p_value": None}]
|
| 153 | apply_claim_fdr(results, fdr=0.05)
|
| 154 | self.assertEqual([r["verdict"] for r in results], ["GREEN", "AMBER", "AMBER"])
|
| 155 | self.assertFalse(results[1]["claim_eligible"])
|
| 156 | self.assertEqual(results[0]["fdr_family_size"], 2)
|
| 157 |
|
| 158 | def test_baseline_builder_rejects_mixed_populations(self):
|
| 159 | with self.assertRaisesRegex(ValueError, "incompatible baseline population"):
|
| 160 | baseline(rows() + rows(runner_class="linux"))
|
| 161 |
|
| 162 | def test_book_v2_roundtrip_and_duplicate_keys_rejected(self):
|
| 163 | book = book_json([baseline()])
|
| 164 | self.assertEqual(book["schema_version"], 2)
|
| 165 | with tempfile.TemporaryDirectory() as tmp:
|
| 166 | path = Path(tmp) / "book.json"
|
| 167 | path.write_text(json.dumps(book))
|
| 168 | cell = next(iter(load_baseline_book(path).values()))
|
| 169 | self.assertTrue(evaluate(cell=cell)["claim_eligible"])
|
| 170 | book["cells"].append(book["cells"][0])
|
| 171 | path.write_text(json.dumps(book))
|
| 172 | with self.assertRaisesRegex(ValueError, "duplicate baseline cell"):
|
| 173 | load_baseline_book(path)
|
| 174 |
|
| 175 | def test_unknown_identity_version_rejected(self):
|
| 176 | book = book_json([baseline()])
|
| 177 | book["cells"][0]["comparison_identity"]["schema_version"] = 99
|
| 178 | with tempfile.TemporaryDirectory() as tmp:
|
| 179 | path = Path(tmp) / "book.json"
|
| 180 | path.write_text(json.dumps(book))
|
| 181 | with self.assertRaisesRegex(ValueError, "unsupported baseline comparison_identity"):
|
| 182 | load_baseline_book(path)
|
| 183 |
|
| 184 | def test_versioned_patch_guard_requires_actual_success(self):
|
| 185 | target = replace(TARGET, guards={"patch_apply_ok": True})
|
| 186 | cell = baseline(rows(patch_oracle_version="apply-tree-v1") + [dict(r, patch_oracle_version="apply-tree-v1") for r in aa_rows()])
|
| 187 | for evidence in (None, False, True):
|
| 188 | candidate = rows("oak_local", patch_oracle_version="apply-tree-v1", patch_apply_ok=evidence)
|
| 189 | result = evaluate_targets(candidate, [target], {cell.key: cell}, mode="claim", bootstrap_samples=20)[0]
|
| 190 | self.assertEqual(result["verdict"], "GREEN" if evidence is True else "INVALID")
|
| 191 |
|
| 192 | def test_failure_only_recall_guard_fails_without_crashing(self):
|
| 193 | target = replace(TARGET, guards={"information_recall_at_least": 1.0})
|
| 194 | cell = baseline()
|
| 195 | result = evaluate_targets(rows("oak_local", returncode=1), [target], {cell.key: cell})[0]
|
| 196 | self.assertEqual(result["verdict"], "INVALID")
|
| 197 |
|
| 198 | def test_nested_fixture_version_normalizes_but_subject_prompt_does_not_compare(self):
|
| 199 | row = rows("oak_local")[0]
|
| 200 | del row["fixture_version"]
|
| 201 | row["fixture"] = {"fixture_version": 1}
|
| 202 | row["task_prompt_id"] = "oak-specific-label"
|
| 203 | self.assertEqual(comparison_identity(row), comparison_identity(rows()[0]))
|
| 204 |
|
| 205 | def test_cli_defaults_to_claim_and_refuses_legacy_evidence(self):
|
| 206 | target = {"schema_version": 1, "targets": [dict(id="t", lane="core", profile="standard",
|
| 207 | scenario="tiny", operation="status.clean", subject="oak_local", comparator="git",
|
| 208 | metric="elapsed_ms", goal=dict(type="ratio_at_most", value=.8))]}
|
| 209 | with tempfile.TemporaryDirectory() as tmp:
|
| 210 | root = Path(tmp)
|
| 211 | (root / "rows.jsonl").write_text("\n".join(json.dumps(row) for row in rows("oak_local")))
|
| 212 | (root / "book.json").write_text(json.dumps(book_json([replace(baseline(), comparison_identity=None)])))
|
| 213 | (root / "targets.json").write_text(json.dumps(target))
|
| 214 | command = [sys.executable, "scripts/scorecard.py", str(root / "rows.jsonl"),
|
| 215 | "--baseline-book", str(root / "book.json"), "--targets", str(root / "targets.json"), "--json"]
|
| 216 | proc = subprocess.run(command, capture_output=True, text=True)
|
| 217 | self.assertEqual(proc.returncode, 1)
|
| 218 | self.assertEqual(json.loads(proc.stdout)[0]["mode"], "claim")
|
| 219 |
|
| 220 |
|
| 221 | class OutcomeReportingTest(unittest.TestCase):
|
| 222 | def test_failure_only_cells_and_unknown_outcomes_stay_visible(self):
|
| 223 | source = [dict(rows()[0], returncode=1, elapsed_ms=999),
|
| 224 | dict(rows()[0], returncode=None), dict(rows()[0], returncode=77)]
|
| 225 | with tempfile.TemporaryDirectory() as tmp:
|
| 226 | path = Path(tmp) / "rows.jsonl"
|
| 227 | path.write_text("\n".join(json.dumps(row) for row in source))
|
| 228 | output = io.StringIO()
|
| 229 | with patch.object(sys, "argv", ["benchmark_stats.py", str(path)]), contextlib.redirect_stdout(output):
|
| 230 | self.assertEqual(benchmark_stats.main(), 0)
|
| 231 | self.assertIn("| `git` | `tiny/status.clean` | 2 | 0 | 1 | 1 | 1 | 0 |", output.getvalue())
|
| 232 | self.assertIn("| 0 | unmeasured |", output.getvalue())
|
| 233 | self.assertNotIn("999", output.getvalue())
|
| 234 |
|
| 235 |
|
| 236 |
|
| 237 | class AgentProducerIdentityTest(unittest.TestCase):
|
| 238 | def test_producer_records_runner_and_explicit_remaining_claim_blockers(self):
|
| 239 | from types import SimpleNamespace
|
| 240 | import agent_workflow as aw
|
| 241 | import workflow_ab
|
| 242 | from oakbench.populations import missing_claim_identity
|
| 243 | with tempfile.TemporaryDirectory() as tmp:
|
| 244 | root = Path(tmp)
|
| 245 | stdout, stderr, prompt = [root / name for name in ("stdout", "stderr", "prompt")]
|
| 246 | for path in (stdout, stderr, prompt): path.write_text("")
|
| 247 | execution = aw.AgentExecution(0, False, 1, stdout, stderr, prompt)
|
| 248 | oracle = SimpleNamespace(elapsed_ms=1, vcs_ms=1, test_ms=1, success=True, checks={}, failure_reason=None,
|
| 249 | changed_files=[], test_returncode=0, test_output_bytes=0, dirty_files_at_end=0, commit_delta=1,
|
| 250 | bytes_written=0, artifact_paths=[])
|
| 251 | with patch.object(aw, "runner_fields", return_value={"runner_class": "dedicated-test", "runner_id": "observed", "runner_profile": {}}):
|
| 252 | row = aw.make_row("synthetic", "2026-09-11T00:00:00Z", "test",
|
| 253 | aw.AgentConfig("test", "codex_exec_json", "provider", Path(sys.executable), "version", "model"),
|
| 254 | workflow_ab.Subject("git", "git", "Git", Path("/git")), workflow_ab.WORKFLOWS["bugfix_test_loop"],
|
| 255 | "agent-default", 0, root, root, 0, 0, execution, oracle, "task", {}, {}, {}, "minimal", "full-docs")
|
| 256 | self.assertEqual(aw.validate_row(row), [])
|
| 257 | identity = comparison_identity(row)
|
| 258 | self.assertEqual(identity["runner_class"], "dedicated-test")
|
| 259 | self.assertEqual(identity["oracle_version"], aw.ORACLE_VERSION)
|
| 260 | self.assertEqual(row["cache_state_reason"], "cache_state_unset")
|
| 261 | self.assertIsNone(row["calibration_version"])
|
| 262 | self.assertTrue(row["calibration_unmeasured_reason"])
|
| 263 | self.assertEqual(missing_claim_identity(identity, "agent", "elapsed_ms", "agent.workflow"), ["cache_state"])
|
| 264 | self.assertEqual(missing_claim_identity(identity, "agent", "tokens", "agent.workflow"), ["calibration_version"])
|
| 265 |
|
| 266 | if __name__ == "__main__":
|
| 267 | unittest.main()
|