Run the eval lane¶
The keyless build (./mvnw verify) mocks the model and proves the scaffolding — the plan
derives, the guardrails gate, the budget holds. It says nothing about whether a schedule is actually
good: relevant to the attendee, balanced, the picks a human expert would make. That is a different
question — the model's judgement, which is non-deterministic and needs a real model to test.
The eval lane answers it, for a small golden set, with an LLM-as-judge. It is tagged
@Tag("eval") and excluded from the default verify gate, so the keyless build stays green and
deterministic. You run it deliberately, with a key.
What it does¶
For each case in the golden set (ScheduleQualityEvalTest.goldenCases()), the lane:
- runs the real agent against a real model for that request;
- applies deterministic gates as a belt — no two sessions share a slot, every session is from the catalog, the item count is sane, and any topic the case says to avoid is absent;
- asks the strong model, via the
ScheduleJudgeagent, for a typedScheduleVerdict—relevanceandbalance(1–5) and anonProfileboolean — and asserts each clears the bar (relevance ≥ 3, balance ≥ 3, on-profile true).
Deterministic gates for the seams; a sampled judge for the judgement — the two halves of a real agent test strategy.
Run it¶
Provide a provider key and select the eval profile (it runs only @Tag("eval") tests):
A key in .env also works (it is loaded into the Spring Environment). Without any key the cases
skip — reported as skipped, not failed — because the live assertions are guarded by a JUnit
assumption; the Spring context still boots, so the wiring stays honest even key-free:
The default build is unaffected and needs nothing:
Read a failure¶
When a case fails, the assertion message carries the judge's own words — e.g.
relevance 2/5 below bar — the schedule leans entirely on Kubernetes and ignores the stated DevEx
and resilience interests. That rationale is the signal: it tells you whether the agent's
judgement slipped, in a sentence, the same way the planning log tells you whether the scaffolding
slipped. Read it, don't re-run and hope.
Extend the golden set¶
Add a case to goldenCases() in ScheduleQualityEvalTest: a request, the tags it must never
contain (e.g. List.of("vendor") for "no vendor keynotes"), and the item-count band. Keep the set
small and representative — an eval lane is a sample, not a proof, and every case costs a real run.
The judge rubric lives in ScheduleJudge; tighten it (or the pass thresholds) as your quality bar
rises.
Where this fits¶
This is the honest complement the workshop's own scope audit calls for
(slides/notes/gaps-and-extensions.md, Gap 10): run-time "trust" as taught in the six labs is
legibility plus bounded invariants, sufficient while a human reads each plan. At the
govern-the-loop horizon (habit 8, and Lab 7's agentic RAG), where no human reads every run, the
judgement has to be checked automatically — and that is exactly what this lane samples.
For the deterministic side of the strategy — mocking the model at the action boundary — see
About the runtime harness and habit 7 in
The eight habits. For routing the judge (it uses the best
role) see Route models by role.