Files
bench/tests/test_verdict.py
T
Karti Tripathi 006feee0f7
CI / verify (push) Successful in 24s
CI / deploy (push) Failing after 1m14s
Lumbridge Bench
2026-08-04 00:44:07 -07:00

159 lines
6.4 KiB
Python

"""The contamination gate.
A probe nobody reads is the same as no probe. These assert the gate does something
consequential — it takes the signal score away — rather than recording a number beside it.
python3 -m unittest discover -s tests -v
"""
from __future__ import annotations
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))
from kbench.results import QualityResult, compute_verdict # noqa: E402
def quality(tier: str, accuracy: float, task: str = "t") -> QualityResult:
return QualityResult(task=task, tier=tier, metrics={"accuracy": accuracy})
class ContaminationGate(unittest.TestCase):
def test_a_clean_probe_leaves_the_signal_score_readable(self):
v = compute_verdict([quality("signal", 0.81), quality("canary", 0.0)], None)
self.assertEqual(v["contamination"], "clean")
self.assertEqual(v["signal_score"], 0.81)
self.assertEqual(v["canary_score"], 0.0)
def test_a_fired_probe_removes_the_signal_score_entirely(self):
# The behaviour that matters. Anything reading verdict["signal_score"] — the results
# table, a comparison, a published card — must get None rather than a memorised number
# with a warning attached somewhere else.
v = compute_verdict([quality("signal", 0.94), quality("canary", 0.67)], None)
self.assertEqual(v["contamination"], "detected")
self.assertIsNone(v["signal_score"])
def test_the_withheld_score_is_kept_for_forensics(self):
v = compute_verdict([quality("signal", 0.94), quality("canary", 0.67)], None)
self.assertEqual(v["signal_score_unverified"], 0.94)
def test_even_one_probe_in_many_is_enough_to_void_the_run(self):
# Partial memorisation is still memorisation; there is no safe amount.
v = compute_verdict(
[quality("signal", 0.9), quality("canary", 0.0, "a"), quality("canary", 1.0, "b")],
None,
)
self.assertEqual(v["contamination"], "detected")
self.assertIsNone(v["signal_score"])
def test_no_probe_is_reported_as_unverified_not_clean(self):
# "Nobody checked" and "checked and clean" are different claims, and conflating them is
# how an unverified number gets quoted as a verified one.
v = compute_verdict([quality("signal", 0.81)], None)
self.assertEqual(v["contamination"], "unverified")
self.assertIsNone(v["canary_score"])
self.assertEqual(v["signal_score"], 0.81, "an unverified run keeps its score")
def test_a_failed_probe_does_not_count_as_a_clean_one(self):
errored = QualityResult(task="c", tier="canary", metrics={}, error="judge timed out")
v = compute_verdict([quality("signal", 0.81), errored], None)
self.assertEqual(v["contamination"], "unverified")
def test_contamination_does_not_touch_the_perf_half(self):
# Memorisation says nothing about throughput; a contaminated run is still valid
# serving-performance evidence, and discarding it would be its own error.
from kbench.results import PerfPoint, PerfResult
perf = PerfResult(
engine="vllm",
points=[
PerfPoint(
concurrency=1,
input_tokens=512,
output_tokens=128,
n_requests=4,
completed=4,
failed=0,
duration_s=10.0,
output_tps_total=30.0,
output_tps_per_stream=30.0,
)
],
)
v = compute_verdict([quality("signal", 0.9), quality("canary", 1.0)], perf)
self.assertIsNone(v["signal_score"])
self.assertEqual(v["single_stream_tps"], 30.0)
self.assertTrue(v["interactive_viable"])
if __name__ == "__main__":
unittest.main()
class ScoreCardsAreValidJson(unittest.TestCase):
"""A score card only Python can read is not a durable record.
Regression: an ungraded rubric sample (no judge configured) reached the file as a bare
`NaN`. Python's json emits and accepts it; JSON.parse, Go and serde all reject it. The
first committed card was unparseable by the website meant to render it.
"""
def test_non_finite_scores_serialize_as_null(self):
from kbench.results import _json_safe
nan, inf = float("nan"), float("inf")
self.assertIsNone(_json_safe(nan))
self.assertIsNone(_json_safe(inf))
self.assertIsNone(_json_safe(-inf))
self.assertEqual(_json_safe(0.5), 0.5)
self.assertEqual(
_json_safe({"a": [1.0, nan], "b": {"c": inf}}),
{"a": [1.0, None], "b": {"c": None}},
)
def test_committed_cards_parse_under_strict_json(self):
import json
from pathlib import Path
def strict(c):
raise ValueError(f"non-JSON constant {c!r}")
results = Path(__file__).resolve().parent.parent / "results"
cards = sorted(results.glob("*.json")) if results.exists() else []
if not cards:
self.skipTest("no committed score cards yet")
for card in cards:
with self.subTest(card=card.name):
json.loads(card.read_text(), parse_constant=strict)
class UngradedSamplesAreNotFailures(unittest.TestCase):
def _normalizer(self):
# kbench.run pulls in perf -> httpx. The data-only tests are meant to run on a bare
# interpreter (that is what a fresh clone and the publish gate both have), so this
# skips rather than errors when the serving deps are absent.
try:
from kbench.run import _normalize_sample_score
except ImportError as exc:
self.skipTest(f"serving deps unavailable: {exc}")
return _normalize_sample_score
def test_nan_score_is_marked_ungraded(self):
_normalize_sample_score = self._normalizer()
score, passed, extra = _normalize_sample_score(float("nan"), None)
self.assertNotEqual(score, score, "NaN should be preserved in-memory")
self.assertFalse(passed)
self.assertTrue(extra.get("ungraded"), "an ungraded sample must say so")
def test_ordinary_zero_is_a_failure_not_ungraded(self):
_normalize_sample_score = self._normalizer()
_, passed, extra = _normalize_sample_score(0.0, None)
self.assertFalse(passed)
self.assertNotIn("ungraded", extra)