test: add scenario eval runner, recorded fixtures, and baseline comparison

This commit is contained in:
Justin Visser 2026-08-10 22:21:04 +02:00
parent 3dc1af5f0c
commit 0664cc2d27
38 changed files with 6986 additions and 5 deletions

79
eval/scenario.py Normal file
View file

@ -0,0 +1,79 @@
"""Load the shared evaluation scenario catalog."""
from dataclasses import dataclass
from pathlib import Path
from typing import cast
import yaml
SCENARIO_PATH = Path(__file__).with_name("scenarios.yaml")
FacetValue = str | bool
@dataclass(frozen=True)
class Scenario:
"""One golden query and its expected intent facets."""
key: str
chip: str
query: str
facets: dict[str, FacetValue]
after: str | None = None
@property
def is_refinement(self) -> bool:
"""Return whether this query follows another scenario."""
return self.after is not None
def load_scenarios(path: Path = SCENARIO_PATH) -> tuple[Scenario, ...]:
"""Read and validate the shared YAML scenario catalog."""
payload = yaml.safe_load(path.read_text(encoding="ascii"))
if not isinstance(payload, dict) or payload.get("version") != 1:
raise ValueError("Scenario catalog must have version 1")
entries = payload.get("scenarios")
if not isinstance(entries, list) or not entries:
raise ValueError("Scenario catalog must contain scenarios")
scenarios = tuple(_parse_scenario(entry) for entry in entries)
keys = [scenario.key for scenario in scenarios]
if len(keys) != len(set(keys)):
raise ValueError("Scenario keys must be unique")
known_keys = set(keys)
for scenario in scenarios:
if scenario.after is not None and scenario.after not in known_keys:
raise ValueError(f"Unknown parent scenario: {scenario.after}")
return scenarios
def _parse_scenario(payload: object) -> Scenario:
if not isinstance(payload, dict):
raise ValueError("Each scenario must be a mapping")
required = {"key", "chip", "query", "facets"}
allowed = required | {"after"}
if set(payload) - allowed or not required <= set(payload):
raise ValueError("Scenario fields must match the catalog schema")
facets = payload["facets"]
if not isinstance(facets, dict) or not facets:
raise ValueError("Scenario facets must be a non-empty mapping")
if not all(
isinstance(key, str) and isinstance(value, (str, bool)) for key, value in facets.items()
):
raise ValueError("Scenario facets must contain string or boolean values")
after = payload.get("after")
if after is not None and not isinstance(after, str):
raise ValueError("Scenario after must be a key")
return Scenario(
key=_required_string(payload, "key"),
chip=_required_string(payload, "chip"),
query=_required_string(payload, "query"),
facets=cast(dict[str, FacetValue], facets),
after=after,
)
def _required_string(payload: dict[object, object], key: str) -> str:
value = payload.get(key)
if not isinstance(value, str) or not value:
raise ValueError(f"Scenario {key} must be a non-empty string")
return value