194 lines
6.5 KiB
Python
194 lines
6.5 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from collections import Counter
|
|
from dataclasses import replace
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
COHORT_PATH = ROOT / "docs" / "thesis" / "agent-challenge-cohort.json"
|
|
|
|
|
|
def test_primary_agent_challenge_cohort_is_complete_and_audited() -> None:
|
|
from examples.agent_challenges.evaluation import load_evaluation_cohort
|
|
|
|
cohort = load_evaluation_cohort(COHORT_PATH, repository_root=ROOT)
|
|
|
|
assert len(cohort.trials) == 36
|
|
assert {trial.wave for trial in cohort.trials} == {1, 2, 3}
|
|
assert Counter(trial.manual_outcome for trial in cohort.trials) == {
|
|
"pass": 27,
|
|
"invalid": 8,
|
|
"fail": 1,
|
|
}
|
|
|
|
cells = Counter(
|
|
(trial.challenge, trial.model, trial.profile) for trial in cohort.trials
|
|
)
|
|
assert len(cells) == 12
|
|
assert set(cells.values()) == {3}
|
|
|
|
|
|
def test_primary_cohort_preserves_automatic_and_manual_outcomes() -> None:
|
|
from examples.agent_challenges.evaluation import load_evaluation_cohort
|
|
|
|
cohort = load_evaluation_cohort(COHORT_PATH, repository_root=ROOT)
|
|
outcome_pairs = Counter(
|
|
(trial.task_outcome, trial.manual_outcome) for trial in cohort.trials
|
|
)
|
|
|
|
assert outcome_pairs == {
|
|
("success", "pass"): 24,
|
|
("success", "invalid"): 7,
|
|
("failed", "pass"): 3,
|
|
("failed", "invalid"): 1,
|
|
("failed", "fail"): 1,
|
|
}
|
|
|
|
|
|
def test_primary_cohort_snapshot_loads_without_local_report_files(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
from examples.agent_challenges.evaluation import load_evaluation_cohort
|
|
|
|
manifest = json.loads(COHORT_PATH.read_text(encoding="utf-8"))
|
|
assert all(len(run["report_sha256"]) == 64 for run in manifest["runs"])
|
|
snapshot = tmp_path / "agent-challenge-cohort.json"
|
|
snapshot.write_text(json.dumps(manifest), encoding="utf-8")
|
|
|
|
cohort = load_evaluation_cohort(snapshot, repository_root=tmp_path)
|
|
|
|
assert len(cohort.trials) == 36
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("field", "value", "message"),
|
|
[
|
|
("profile", "debug", "unsupported evaluation profile"),
|
|
("task_outcome", "unknown", "unsupported task outcome"),
|
|
("audit_notes", ["not", "text"], "audit_notes must be a string"),
|
|
],
|
|
)
|
|
def test_evaluation_cohort_rejects_unknown_or_mistyped_run_values(
|
|
tmp_path: Path, field: str, value: object, message: str
|
|
) -> None:
|
|
from examples.agent_challenges.evaluation import load_evaluation_cohort
|
|
|
|
manifest = json.loads(COHORT_PATH.read_text(encoding="utf-8"))
|
|
manifest["runs"][0][field] = value
|
|
snapshot = tmp_path / "agent-challenge-cohort.json"
|
|
snapshot.write_text(json.dumps(manifest), encoding="utf-8")
|
|
|
|
with pytest.raises(ValueError, match=message):
|
|
load_evaluation_cohort(snapshot, repository_root=tmp_path)
|
|
|
|
|
|
def test_evaluation_figures_reject_unknown_direct_trial_values() -> None:
|
|
import matplotlib.pyplot as plt
|
|
|
|
from examples.agent_challenges.evaluation import load_evaluation_cohort
|
|
from examples.agent_challenges.evaluation_figures import (
|
|
_automatic_vs_manual,
|
|
_scatter_metric,
|
|
)
|
|
|
|
cohort = load_evaluation_cohort(COHORT_PATH, repository_root=ROOT)
|
|
figure, axis = plt.subplots()
|
|
try:
|
|
with pytest.raises(ValueError, match="unsupported evaluation model"):
|
|
_scatter_metric(
|
|
axis,
|
|
[replace(cohort.trials[0], model="unknown-model")],
|
|
metric="duration",
|
|
)
|
|
with pytest.raises(ValueError, match="unsupported evaluation profile"):
|
|
_scatter_metric(
|
|
axis,
|
|
[replace(cohort.trials[0], profile="unknown-profile")],
|
|
metric="duration",
|
|
)
|
|
invalid_cohort = replace(
|
|
cohort,
|
|
trials=(replace(cohort.trials[0], task_outcome="unknown"),),
|
|
)
|
|
with pytest.raises(ValueError, match="unsupported task outcomes"):
|
|
_automatic_vs_manual(invalid_cohort, plt)
|
|
finally:
|
|
plt.close(figure)
|
|
|
|
|
|
def test_evaluation_generator_prints_paths_outside_repository(
|
|
tmp_path: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
capsys: pytest.CaptureFixture[str],
|
|
) -> None:
|
|
from docs.thesis import generate_agent_challenge_evaluation as generator
|
|
|
|
generated = tmp_path / "agent-challenge-results.md"
|
|
monkeypatch.setattr(
|
|
generator,
|
|
"generate",
|
|
lambda **_kwargs: (generated,),
|
|
)
|
|
|
|
assert generator.main(["--output-dir", str(tmp_path)]) == 0
|
|
assert capsys.readouterr().out.strip() == "agent-challenge-results.md"
|
|
|
|
|
|
def test_evaluation_renderer_writes_stable_svg_and_pdf_names(tmp_path: Path) -> None:
|
|
from examples.agent_challenges.evaluation import (
|
|
FIGURE_STEMS,
|
|
load_evaluation_cohort,
|
|
render_evaluation_figures,
|
|
)
|
|
|
|
cohort = load_evaluation_cohort(COHORT_PATH, repository_root=ROOT)
|
|
written = render_evaluation_figures(cohort, tmp_path)
|
|
|
|
expected = {
|
|
tmp_path / f"{stem}.{suffix}"
|
|
for stem in FIGURE_STEMS
|
|
for suffix in ("svg", "pdf")
|
|
}
|
|
assert set(written) == expected
|
|
assert all(path.stat().st_size > 0 for path in written)
|
|
|
|
|
|
def test_evaluation_figures_are_byte_stable_across_regeneration(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
from examples.agent_challenges.evaluation import (
|
|
load_evaluation_cohort,
|
|
render_evaluation_figures,
|
|
)
|
|
|
|
cohort = load_evaluation_cohort(COHORT_PATH, repository_root=ROOT)
|
|
first = render_evaluation_figures(cohort, tmp_path)
|
|
first_bytes = {path.name: path.read_bytes() for path in first}
|
|
|
|
second = render_evaluation_figures(cohort, tmp_path)
|
|
|
|
assert {path.name: path.read_bytes() for path in second} == first_bytes
|
|
|
|
|
|
def test_evaluation_markdown_states_counts_and_longitudinal_limit() -> None:
|
|
from examples.agent_challenges.evaluation import (
|
|
load_evaluation_cohort,
|
|
render_evaluation_markdown,
|
|
)
|
|
|
|
cohort = load_evaluation_cohort(COHORT_PATH, repository_root=ROOT)
|
|
markdown = render_evaluation_markdown(cohort)
|
|
|
|
assert "36 manually audited trials" in markdown
|
|
assert "27 clean product-path passes under the campaign rules" in markdown
|
|
assert "not a model-success-rate estimate" in markdown
|
|
assert "8 invalid evaluation samples" in markdown
|
|
assert "and 1 failure" in markdown
|
|
assert "not a controlled model comparison" in markdown
|
|
assert "agent-challenge-audited-outcomes-by-cell.svg" in markdown
|
|
assert "agent-challenge-longitudinal-outcomes.svg" in markdown
|
|
assert "Figure [@fig:" not in markdown
|