AI Operations · B10–B27wk 8 / 54
B10 · measurement · Live operation

Evaluation Harness. The Foundation

Status
shipped
Weeks
1–3
Permission gate
none
Depends on
nothing
Page depth
full

Why this block exists

Scheduled here because it has zero upstream dependencies. Everything measured before a measurement layer exists is retrofitted and unverifiable, and that's the single biggest correction I made to the plan's original ordering. The bet: build the ruler before the thing it measures, so the golden set can't drift toward whatever the system under test already happens to handle well.

What I built

agenteval, an evaluation harness for AI agents, as a real Python package instead of a one-off script: HTTP and CLI adapters, a golden-set format that requires labeling rationale (not optional), Wilson confidence intervals on every reported rate, pass^k reliability testing, and a cross-model LLM-as-judge pipeline that has to validate against independent human labels before I trust it for anything.

What I did

Week 1 was methodology before touching real data: the golden-set spec, a prediction sheet, a first interface-contract sketch. The proof that the delay was worth it came from an old 22-case classifier sitting around from an earlier block. Running a Wilson interval on its "95.5% accurate" result turned that into "somewhere between 78% and 99%." Not the same claim at all.

Week 2 built the harness for real and pointed it at the actual target: Block 8 Copilot, a production support-ticket classifier. 50-case golden set across 5 case types, coverage runs, reliability runs, first real numbers back.

Week 3 added the piece the schedule had pushed off: an LLM judge (Claude Sonnet, deliberately cross-model against Copilot's GPT-4o) validated against independent human labels using Cohen's kappa. I also built a second worked example, expense_router, specifically to check whether the fix Copilot needs actually holds up when someone builds it for real.

What came out of it

Copilot scored 66.0% pass@1 (95% CI: 52.2%–77.6%). The number underneath that mattered more: 0% on all 10 should-abstain cases, fully deterministic across all 80 pass^8 attempts. I checked the system's own prompt directly. It hard-codes 5 categories, no abstain option anywhere in the schema. It's not that the model failed to learn restraint. It was never given anywhere to put an answer it shouldn't guess at. A prompt-injection attempt landed as "Feature Request" at 93% confidence, statistically no different from its confidence on cases it got right.

The pass@1-to-pass^8 gap was smaller than I expected too: 39.3% to 35.7%, a 3.6-point gap on the 28-case reliability subset, with 26 of 28 cases perfectly consistent across all 8 runs. So Copilot isn't randomly unreliable on hard cases. It's consistently and confidently wrong on an identifiable subset. That's a design gap, not a tuning problem.

The judge validated at 84.0% raw agreement with independent human labels, Cohen's kappa = 0.654 ("substantial"), and every disagreement clustered in the case types where you'd actually expect judgment-call variance (ambiguous, multi-intent), not the unambiguous ones. Getting to that number meant catching my own mistake first. The first human-labeling pass scored all 10 should-abstain cases "pass" even though the written reasoning argued the opposite. Uncorrected, that would've produced a kappa of 0.060 and made the judge look nearly useless. I caught it by checking whether the stated reasoning actually matched the score before trusting the labels. No automated check flagged it.

expense_router, a second and deliberately different system (CLI instead of HTTP, deterministic rule-based instead of an LLM), tested the fix Copilot needed: an explicit "needs human review" path checked before any categorization is attempted. 100% on should-abstain and adversarial cases, first run, no tuning. Same harness, zero code changes to run it against a completely different kind of agent.

What I'd change

Build Copilot's rejection path as deterministic pre-processing ahead of the classifier. Pattern-match empty/gibberish input, injection markers, and PII-disclosure requests before the ticket ever reaches the model, and route those straight to human escalation regardless of what the model would've said. Should-abstain scored a fully deterministic 0%, so this isn't a better-prompting problem. It needs an explicit code path, which is exactly what expense_router proves out.

What carries forward

The evaluation discipline built here (labeled golden sets with mandatory rationale, Wilson intervals on every rate, pass^k for anything claiming reliability, cross-model judges validated against humans before they're trusted) is now what every later block gets measured against. The should-abstain finding also changes what Block 11's advisory bot has to prove before it goes near a real repository. Giving good suggestions isn't enough if it has no way to say it doesn't know.

Full write-up, including the actual numbers, disagreement detail, and the LinkedIn version: see the artifacts above, or "What pass@1 hides" in Writing.

01What it has to teach me

topicpass^k reliability methodology
topicLLM-as-judge validation
topicgolden set design
topicconfidence intervals
topicagent interface contracts

02Predictions, and what actually happened

Written beforehandActualVerdict
No Week 1 prediction sheet was recorded before the first coverage run.The sheet was still empty going into Week 3, so there was nothing to check the pass@1 result against.A real process failure, disclosed rather than backfilled after the fact. See 'A Methodology Lapse Disclosed' in the Block 8 analysis doc. Fixed going forward: the sheet gets filled in and committed before the first coverage run, not after.

03Measured results

MetricValueHow it was measured
Block 8 Copilot — pass@1 (n=50)66.0% (95% CI: 52.2%–77.6%)One run per golden-set case, scored against expected output.
Block 8 Copilot — should-abstain cases (n=10)0.0% at pass@1, 0/80 across pass^8 — fully deterministic zeroTraced to the system's own prompt: 5 hard-coded categories, no abstain/escalate option in the schema at all.
Block 8 Copilot — pass@1 vs pass^8 gap (n=28 reliability subset)39.3% → 35.7% (3.6-point gap); 26 of 28 cases were perfectly deterministic (8/8 or 0/8)Each case in the ambiguous + should-abstain + multi-intent subset run 8 times, k=8.
LLM judge vs. independent human labels84.0% raw agreement, Cohen's kappa = 0.654 ("substantial")Claude Sonnet judge (deliberately cross-model against Copilot's GPT-4o) scored all 50 real coverage-run outputs; compared against 50 human labels made blind to the judge's scores.
expense_router (second worked example) — pass@1 (n=16)87.5% (95% CI: 64.0%–96.5%); should-abstain and adversarial cases both 100%Same harness, zero code changes to core.py/scenario.py — different transport (CLI, not HTTP), different agent (deterministic rule-based, not an LLM).

04What I rejected

Rejected

Building a deterministic pre-classifier gate into Block 8 Copilot to fix its should-abstain gap. — Documented and scoped as a recommendation, not built. Folding an unplanned Copilot rebuild into B10 would've blurred the actual deliverable, which is the harness itself. expense_router is that same fix, built for real, on a system scoped for it.

05Judgment calls

Decided not to automate. A second independent labeler on the ambiguous and multi-intent cases, the ones where the judge and my single human labeler actually disagreed. One labeler is enough to catch a labeling error (which happened, see surprised below) but not enough to know whether the golden set's labeling_rationale field actually holds up when someone who didn't write it has to defend it.

What surprised me. How small the pass@1-to-pass^8 reliability gap actually was: 3.6 points, 26 of 28 cases perfectly deterministic across all 8 runs. I expected repetition to expose hidden flakiness. Instead it mostly confirmed the opposite: Copilot's failures are structural and repeatable, not random, which changes the fix from "improve the model" to "add a code path that doesn't exist yet."

06Artifacts

repoagenteval (GitHub)docBlock 8 Copilot evaluation resultsdocLLM judge validation reportdocSecond worked example: expense_routerdocInterface contract spec v1docRejection log

07Evidence still missing

emptyScreenshot of a coverage run's terminal output

STACK · Python · pytest · Claude Sonnet (LLM-as-judge) · Wilson Confidence Intervals · pass^k Reliability Testing · Cohen's Kappa

2026-09-01Outline created from the AI Operations Roadmap (B10-B27).
2026-09-11Full write-up: real coverage/reliability results, judge validation, second worked example, and rejection log.
← B8 Smart Reply Copilot: Multi-Step Prompt ChainingB11 Surface Zero Goes Live →