amana / eval /build_testset.py
Misbahuddin's picture
Phase 4: eval harness + CI (deterministic safety gate + LLM-judge)
9561b34
Raw
History Blame Contribute Delete
2.49 kB
"""Generate `eval/testset.json` from the campaigns' private `_expected` ground truth.
Each campaign file carries a private `_expected` block (recommendation + the rule IDs a
correct adjudication should rest on). That block is stripped before the agent ever sees the
campaign (`src/campaigns.load_campaign`); only the eval harness is allowed to read it via
`load_expected`. This script collects those blocks into a single committed test set so the
eval and CI have a stable, reviewable ground-truth file.
python -m eval.build_testset # writes eval/testset.json
python -m eval.build_testset --check # verify the committed file is up to date (CI)
"""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from src.campaigns import list_campaign_paths, load_expected
TESTSET_PATH = Path("eval/testset.json")
def build() -> list[dict]:
"""Collect every campaign's `_expected` into a list of test cases."""
cases: list[dict] = []
for path in list_campaign_paths():
expected = load_expected(path)
if not expected:
continue # a campaign without ground truth is not part of the eval set
cases.append(
{
"id": path.stem,
"path": path.as_posix(),
"expected": {
"recommendation": expected["recommendation"],
"primary_rules": expected.get("primary_rules", []),
},
}
)
return cases
def _dump(cases: list[dict]) -> str:
return json.dumps(cases, indent=2, ensure_ascii=False) + "\n"
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--check",
action="store_true",
help="Exit non-zero if eval/testset.json is missing or out of date (do not rewrite).",
)
args = parser.parse_args()
cases = build()
rendered = _dump(cases)
if args.check:
current = TESTSET_PATH.read_text(encoding="utf-8") if TESTSET_PATH.exists() else ""
if current != rendered:
raise SystemExit(
f"{TESTSET_PATH} is out of date — run `python -m eval.build_testset` and commit."
)
print(f"{TESTSET_PATH} is up to date ({len(cases)} cases).")
return
TESTSET_PATH.write_text(rendered, encoding="utf-8")
print(f"Wrote {TESTSET_PATH} ({len(cases)} cases).")
if __name__ == "__main__":
main()