Offline quality eval
The quality eval is the fleet's ground-truth correctness regression alarm. CI gates syntax, types, lints, and the tests a change ships; it cannot see whether a routing, effort, or model change quietly made the agents worse at solving problems. The dominant failure class the fleet produces — semantic-invariant bugs, wrong edge-case behavior, silently dropped requirements — passes every mechanical gate. The quality eval is the standing signal for that class.
It works by re-implementing recently-landed issues blind and scoring the
result against what actually merged. The local manual harness selects samples,
runs a fresh agent against each one with no access to the merged solution, and
judges each blind candidate diff against the landed "ground truth" diff. Its
output is a verdict-rate table grouped by the managed Plan's Size and
Implementation model values — the axes a routing change moves. It runs off
the merge critical path and never gates a PR.
The probe arc this productizes (2026-07-13/14) already found that effort level barely moves correctness below large work, that Opus-medium beats Sonnet-xhigh on large work, and that the failure class is invisible to CI. The eval turns that one-off finding into a repeatable measurement.
What "ground truth" means
The landed squash commit is the ground truth. It merged, so it passed review and CI and represents an accepted solution to the issue. A blind re-implementation is scored against it: not "does it match byte-for-byte" — a different but functionally equivalent implementation is correct — but "does it solve the issue with the same behavior, free of the checklist's semantic-defect classes".
The manual harness
The harness is four local scripts/ files. The select, run, and judge stages
stream newline-delimited JSON to the next, so they compose in a pipe and each is
independently runnable from a fixed input; the fourth file unit-tests their pure
logic.
1. Select — scripts/quality-eval-select.mjs
Enumerates merged PRs from the trailing window (QUALITY_EVAL_WINDOW_DAYS,
default 7) that closed a code-bearing issue (the squash commit touched a
crate source file). For each, it resolves the closing squash commit and its
parent SHA — the pre-merge trunk tip the blind run clones at — and captures,
at selection time, the closing issue body plus the Size and Implementation model values parsed from its valid managed Plan. It then deterministically
samples QUALITY_EVAL_SAMPLE_SIZE (default 5) and emits one record per line:
{"issue":123,"pr":456,"squash_sha":"…","parent_sha":"…","model":"opus","size":"l","issue_body":"…"}
The sample is deterministic (ordered by a stable hash of each candidate's SHA) so a re-run over the same candidate set reproduces the same sample. The body is the runner's task input and the normalized routing values feed the judge's aggregation. They are captured together so a later issue edit cannot change the meaning of a selected sample.
2. Run — scripts/quality-eval-run.sh
The blind runner. Per sample it builds a sealed scratch repo and runs an isolated coding agent against the issue body, then harvests the candidate diff beside the landed ground-truth diff, emitting:
{"issue":123,"candidate_diff":"…","landed_diff":"…","model":"opus","size":"l"}
Blindness is structural, not a matter of trusting the agent:
- Single-revision clone.
git clone --revision=<parent_sha> --depth=1(git ≥2.49) makesparent_shathe only reachable commit — the landed squash commit is reachable from no ref in the scratch repo. - Sealed remote. The clone's
originis removed immediately, so the agent cannotgit fetchtrunk even on a public repo. - Contamination assert. Before the agent runs,
git rev-list --allmust not contain the squash SHA. A hit fails that sample loudly rather than reporting a possibly-peeked verdict — a contaminated scratch would silently inflate the "correct" rate, the exact failure this design guards against. - Edit-only isolation. The agent runs under an
--allowedToolsallowlist (Read / Edit / Write / Grep / Glob / Bash for build+test — noWebFetch, no MCP, nogh) with no GitHub token in its env. This is a belt on top of the structural seal, not the primary guarantee.
The no-token / no-gh constraint scopes to the coding-agent invocation only —
the driver script itself uses git and the network to clone and to read the landed
diff from the full-history checkout.
3. Judge — scripts/quality-eval-judge.mjs
Drives a judge model over each record, comparing the candidate diff to the landed
diff under a fixed known-failure-mode checklist (semantic-invariant, boundary,
error-handling, incomplete, wrong-default, regression). It parses a structured
per-sample verdict (correct / defect, with a defect class) and aggregates
verdict rates grouped by size and model, printing the rollup
markdown. The defect rate is computed over scored (correct + defect) samples —
an unparseable verdict is counted but never scores as correct.
Only the pure logic is unit-tested (scripts/quality-eval.test.mjs): the
selector's trailing-window filter and deterministic sampler, and the judge's
verdict parser and rate aggregation (with a tripwire on the aggregated rates).
The git isolation and the claude invocations are I/O, verified by the
contamination assert at runtime rather than by a test.
Running it manually
Quality evaluation is a local manual harness, not a hosted merge gate. Run it
with git ≥2.49, node, jq, and a CLAUDE_CODE_OAUTH_TOKEN:
GITHUB_TOKEN=$(gh auth token) node scripts/quality-eval-select.mjs > samples.jsonl
QUALITY_EVAL_CLONE_TOKEN=$(gh auth token) bash scripts/quality-eval-run.sh samples.jsonl > judged.jsonl
node scripts/quality-eval-judge.mjs judged.jsonl # prints the rollup
Reading the verdict rates
The rollup reports, per managed-Plan size × model cell and overall, how many blind
re-implementations were judged, how many were correct, how many carried a defect,
and the defect rate over the scored samples, followed by a per-defect list naming
the issue and its defect class. A defect rate that climbs after a routing / effort
/ model change — especially on large work, where the probe arc found the model
choice matters most — is the signal that the change degraded correctness in a way
no other check would surface. A single five-sample run is noisy; repeat runs using
the same sampling method over time before treating movement as a trend.