Iterates on a failing AI/LLM eval (an L2 suite, a golden-set / judge eval, or any eval gating a PR) until it is green AND confirmed, not just luckily passing once. Classifies the failure as a code bug, an eval-definition bug (stale golden item / criteria drift), judge-drift (silent grader version change), or flaky. Applies the minimal fix, then requires N consecutive confirming re-runs — 2 deterministic, 5 for anything a model call grades, since a flat "2" is statistically weak for a stochast...
Scanned 9/3/2026
Install to Claude Code
npx -y skills add mthines/agent-skills --skill eval-iterate --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Eval Iterate?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/mthines-eval-iterate)More formats (shields.io, HTML) on the badges page.
---
name: eval-iterate
description: >
Iterates on a failing AI/LLM eval (an L2 suite, a golden-set / judge
eval, or any eval gating a PR) until it is green AND confirmed, not
just luckily passing once. Classifies the failure as a code bug, an
eval-definition bug (stale golden item / criteria drift), judge-drift
(silent grader version change), or flaky. Applies the minimal fix, then
requires N consecutive confirming re-runs — 2 deterministic, 5 for
anything a model call grades, since a flat "2" is statistically weak
for a stochastic judge. Hard-capped at 5 fix iterations. Refuses to
game the eval (Goodhart's Law: skip/delete/overwrite-in-place a case,
loosen a threshold) without a second independent check plus
`confidence(analysis) >= 90%` and a logged rationale. Composes
`ai-engineering`, `confidence`, `critical`, `verify-behavior`. Use when
an eval is failing on a PR and needs a real, non-gamed green. Triggers
on "this eval is failing", "iterate on this eval", "fix this eval",
"get this eval green", "optimize this eval", "/eval-iterate".
disable-model-invocation: false
argument-hint: '[<eval-target>|<pr-url>] [--max-iterations <n>]'
license: MIT
metadata:
author: mthines
version: '1.1.0'
workflow_type: command
tags:
- evals
- ai-engineering
- iteration-loop
- confidence-gate
- check-gaming
- golden-set
- llm-as-judge
- judge-drift
- confirmation
---
# Eval Iterate
Drive a failing AI/LLM eval to a real green: diagnose, fix, re-run,
confirm — capped at 5 iterations, never by weakening the eval.
This `SKILL.md` is the **orchestration index**.
Load the matching rule file when you need detail — do not preload them.
| Phase | Goal | Required rule |
| ----- | ---- | ------------- |
| 0 | Resolve the target eval + capture the baseline failure | this file |
| 1 | Resolve how to run it | this file |
| 2 | Classify the failure (verdict required) | [`rules/eval-bug-classification.md`](./rules/eval-bug-classification.md) |
| 3 | Apply the minimal fix — gated if it touches the eval itself | [`rules/anti-gaming-guard.md`](./rules/anti-gaming-guard.md) |
| 4 | Re-run, then confirm with a second run | [`rules/convergence-confirmation.md`](./rules/convergence-confirmation.md) |
| 5 | Iterate or stop at the cap | this file |
| 6 | Report (structured exit summary) | this file |
Always read [`rules/anti-gaming-guard.md`](./rules/anti-gaming-guard.md)
before touching any eval definition (assertion, threshold, golden-set
item, judge prompt). The refusals in it apply on every iteration.
## Input
The user provides one of:
- An eval identifier — an L2 suite name (e.g. `tier-routing`), a golden-set
file path, or a test/eval file path.
- A PR URL with a failing eval check.
- **Nothing** — if `$ARGUMENTS` is empty, auto-detect the failing eval
check on the current branch's open PR (see Phase 0).
- `--max-iterations <n>` — lowers the cap below 5. **Never raises it.** A
value above 5 is clamped to 5, not honored.
The argument is: `$ARGUMENTS`.
## Phase 0 — Resolve the target + capture the baseline
If `$ARGUMENTS` is empty, do not ask the user — resolve automatically:
1. Get the current branch and its open PR:
```bash
git rev-parse --abbrev-ref HEAD
gh pr list --head "<branch>" --state open --json number,url --limit 1
```
2. List failing checks and find the one that is an eval (name contains
`eval`, `l2`, or matches a known suite):
```bash
gh pr checks <pr-number> --repo <owner/repo>
```
3. If exactly one failing eval check is found, use it as the target. If
more than one, list them and ask the user which to iterate on first —
this skill iterates on **one target at a time**. If none is found,
report that and stop; there is nothing to iterate on.
Whatever the source, before doing anything else, **run the target once and
capture the raw failure** (exit code, stderr/stdout, the specific
assertion or suite that failed). Never start from a remembered or assumed
failure — the baseline is evidence, not a guess. This raw output is
`BASELINE_FAILURE` and is quoted in the Phase 6 report.
If the target's grading involves any model call (an LLM-as-judge
assertion, a model-scored golden-set item), also record `JUDGE_MODEL` —
the grader model name + version — at this same baseline moment. A silent
grader-version change between baseline and confirmation is a distinct
failure mode (`judge-drift`, Phase 2) that a code-only diff would miss
entirely.
Print the resolved target before continuing:
`Target: <eval identifier> on branch <branch> (cap: <n>/5)`.
## Phase 1 — Resolve how to run it
Discovery order (stop at the first that matches):
1. **This repo's own suites** — if the target names an L1 check or an L2
suite key from `scripts/eval/l2.mjs`'s `SUITES`:
```bash
node scripts/eval/l1.mjs # deterministic contract checks
ANTHROPIC_API_KEY=… node scripts/eval/l2.mjs --suite <name> # behavioral suite
```
2. **Project eval script** — check `package.json` for an `eval`, `evals`,
or `test:eval` script and run that.
3. **CI workflow step** — read the `.github/workflows/*.yml` step whose
name matches the failing check and extract its exact run command.
4. **Ask** — if none of the above resolves a command, ask the user for the
exact command that runs this eval. Do not guess a command and run it
speculatively against a repo you do not understand.
Record the resolved command as `RUN_CMD`. Every re-run in this skill uses
the same `RUN_CMD` — changing the run command mid-loop invalidates the
comparison between iterations.
Also classify the target's **grading path** once, here — it decides the
Phase 4 confirmation bar: does any part of `RUN_CMD`'s pass/fail decision
involve a model call (an LLM-as-judge assertion, a model-scored
golden-set item), or is it purely deterministic (exit code, type/schema
check, string/regex assertion)? Record this as `GRADING_PATH` (`judge` or
`deterministic`). See
[`rules/convergence-confirmation.md`](./rules/convergence-confirmation.md).
## Phase 2 — Classify the failure (verdict required)
Pick exactly one verdict per iteration before writing anything.
Full decision table, signals, and per-verdict notes:
[`rules/eval-bug-classification.md`](./rules/eval-bug-classification.md).
Verdicts at a glance:
- `code-bug` — the code under test is wrong; the eval correctly caught it.
- `eval-bug` — the eval itself is wrong (stale golden item, miscalibrated
judge, wrong assertion, threshold set without basis). Tag it with a
subtype — `mis-specified` (the eval's existing logic is simply wrong)
or `stale-criteria` (the eval never anticipated this case — legitimate
criteria drift, not a mistake) — per
[`rules/eval-bug-classification.md`](./rules/eval-bug-classification.md).
- `judge-drift` — `GRADING_PATH` is `judge`, and the grader model name +
version now serving the re-run differs from the `JUDGE_MODEL` recorded
at baseline. The fix is pinning the grader version, not editing the
eval or the code — see
[`rules/eval-bug-classification.md`](./rules/eval-bug-classification.md).
- `flaky` — re-run `RUN_CMD` once immediately, unchanged, with
`JUDGE_MODEL` confirmed unchanged. If it now passes, note the flake and
treat non-determinism itself as an `eval-bug` (an eval that isn't
reproducible is broken) rather than spending a fix iteration guessing
at a code change.
- `unsure` — the failure output does not clearly support any of the
above. Do not guess. Use `Skill("ai-engineering", "review <target>")`
scoped to the evals area for a second look; if still unsure after that,
stop and escalate to the user with the raw evidence rather than burning
iterations on speculative fixes.
## Phase 3 — Apply the minimal fix
- `code-bug` → fix the code under test. No eval file is touched. Normal
code-change discipline applies (smallest change that fixes the root
cause, consistent with the surrounding code).
- `judge-drift` → pin the grader model version in the eval's own config.
No assertion, golden item, or code is touched.
- `eval-bug` → **read
[`rules/anti-gaming-guard.md`](./rules/anti-gaming-guard.md) before
editing anything.** Every edit to an assertion, threshold, golden-set
item, or judge prompt requires (1) a second independent check — a
fresh `Skill("critical", "analysis")` pass or explicit user
confirmation, not just this run's own self-graded score, (2)
`confidence(analysis) >= 90%`, and (3) a logged rationale — no
exceptions, no matter how obviously "just a typo in the expected
value" it looks.
Hard refusals (full list, including Goodhart's-Law framing, in
[`rules/anti-gaming-guard.md`](./rules/anti-gaming-guard.md)):
- Never skip, delete, `.skip`/`xfail`, or exclude a failing case to make
the suite pass.
- Never loosen a threshold, gate percentage, or assertion without a
logged, evidence-backed rationale and the gates above.
- Never overwrite an existing golden-set case in place — a legitimate
correction adds a new/superseding case and keeps the original runnable
as a regression guard.
- Never suppress or catch the eval framework's failure exit code.
- Never disable the CI step that runs this eval (`continue-on-error`,
removing it from `paths:`, etc.).
## Phase 4 — Re-run, then confirm
`N` is the confirmation bar decided at Phase 1's `GRADING_PATH`
classification: **2** for `deterministic`, **5** for `judge`. Full
rationale and procedure in
[`rules/convergence-confirmation.md`](./rules/convergence-confirmation.md).
1. Run `RUN_CMD`. If it fails, this iteration did not succeed — go to
Phase 5 (do not stop here and call it done).
2. If it passes, **do not declare victory on one pass.** Run `RUN_CMD`
again, unchanged, for a total of `N` consecutive passes. Stop at the
first failure inside that window — a single fail disproves
`CONFIRMED` regardless of how many runs already passed; treat it as a
failed iteration and continue, not a flake to explain away.
3. If `GRADING_PATH` is `judge`, all `N` passes is evidence the fix isn't
a fluke — it is not proof the judge itself is well-calibrated
(repeated sampling cancels random noise, not a systematically wrong
judge). Do not overstate `CONFIRMED` as more than that.
## Phase 5 — Iterate or stop at the cap
- `CONFIRMED` → stop. Go to Phase 6 with outcome `confirmed-green`.
- Not confirmed, and iterations used < cap (default 5, never raised past
5 by `--max-iterations`) → increment the iteration counter, return to
Phase 2 with the latest failure output as new evidence. Do not repeat
the same fix that already failed to confirm — the new evidence must
change the classification or the fix, or the loop is not converging and
should stop early rather than spend the remaining budget on repetition.
- Not confirmed, and iterations used == cap → stop. Go to Phase 6 with
outcome `max-iterations`. **Do not continue past the cap under any
circumstance**, including a user re-request mid-loop — a fresh
invocation with an explicit reset is a new run, not an extension of this
one.
## Phase 6 — Report
Always end with a structured summary, regardless of outcome:
```text
eval-iterate run
Outcome: <confirmed-green | escalated | max-iterations>
Target: <eval identifier> (<RUN_CMD>)
Grading path: <deterministic | judge> JUDGE_MODEL: <name+version, if judge>
Baseline failure: <one-line cause, quoting BASELINE_FAILURE>
Iterations: <N>/<cap>
Per-iteration verdicts: <code-bug | eval-bug(subtype) | judge-drift | flaky | unsure>, ...
Eval-definition edits: <none | one entry per edit — see rules/anti-gaming-guard.md's log format>
Confirmation: <N-of-N consecutive green runs of RUN_CMD, N per grading path | not reached>
```
On `confirmed-green`, include the fix applied per iteration and the final
confirming run outputs (or a pointer to them).
On `max-iterations` or `escalated`, include what was tried per iteration,
the current best hypothesis, and what a human should look at next. Never
present a still-failing or unconfirmed eval as passing.
## Required Reading by Phase
Load on demand — do not preload.
| Phase | Files |
| ----- | ----- |
| 2 | [`rules/eval-bug-classification.md`](./rules/eval-bug-classification.md) |
| 3 | [`rules/anti-gaming-guard.md`](./rules/anti-gaming-guard.md) |
| 4 | [`rules/convergence-confirmation.md`](./rules/convergence-confirmation.md) |
## Composition, not reimplementation
This skill is a thin loop around three existing skills — it never
reimplements their logic:
- **`ai-engineering`** (evals concern, `rules/evals.md`) owns the eval
methodology this skill's classification draws on: error-analysis-first,
golden-set sizing, LLM-as-judge bias mitigations, narrow rubrics.
Dispatch it with `Skill("ai-engineering", "review <target>")` when
Phase 2's classification needs a second opinion.
- **`confidence`** (`analysis` mode) owns the score gating any
eval-definition edit. This skill never invents its own scoring rubric —
it calls `Skill("confidence", "analysis")` and reads the `Final` score.
- **`critical`** (`analysis` mode) supplies the second, independent check
an eval-definition edit needs beyond the fixing agent's own confidence
score — dispatch it fresh, without the proposed edit already in its
context, to challenge the rationale adversarially.
- **`verify-behavior`** (`change` mode) owns the execute-and-receipt
mechanic for the re-run in Phase 4. This skill supplies the
`expected: "RUN_CMD exits 0"` framing; `verify-behavior` supplies the
isolated execution and the receipt.
If a companion skill is not installed in the current environment, fall
back to running the equivalent step in-context (e.g. score the
eval-definition edit yourself using `confidence`'s `analysis` dimensions
table) rather than skipping the gate.
## Core Principles
1. **Confirmed, not merely green.** A single pass proves nothing about a
flaky suite or a lucky sample. The bar scales with how the eval grades:
2 consecutive passes for a deterministic check, 5 for anything a model
call scores — binomial statistics make a flat "2" indefensible for a
stochastic judge. See
[`rules/convergence-confirmation.md`](./rules/convergence-confirmation.md).
2. **Classify before you touch anything.** A code-bug and an eval-bug look
identical from the failure output alone until you read the eval's own
logic — guessing wrong wastes an iteration and, worse, can mask a real
regression as an eval problem. A silent judge-version bump is a third,
easy-to-miss possibility — check `JUDGE_MODEL` before blaming the code
or the eval.
3. **The eval is not free to edit, and self-review doesn't count.** Treat
it like `checks.yaml`'s executor-immutable spirit: any loosening edit
needs a second independent check, a confidence gate, and a written
rationale — never a silent fix-to-pass, and never a single agent
grading its own proposed edit. This is Goodhart's Law in four shapes
(regressive, extremal, causal, adversarial) — see
[`rules/anti-gaming-guard.md`](./rules/anti-gaming-guard.md).
4. **The cap is hard.** 5 iterations, never more, regardless of how close
the last run looked — a pragmatic ceiling, not a number derived from
eval-specific research. A loop that isn't converging by iteration 5
needs a human, not iteration 6.
5. **Evidence over assumption.** Every classification and every re-run is
grounded in an actual command's actual output — never "it should pass
now."
6. **A corrected case is a new case, not an edit.** The failing golden
item is itself the strongest evidence a real failure mode exists;
overwriting it in place destroys the regression guard it represents.
## Anti-patterns (one-liners — full list in the rules)
- Declaring victory on a single green run — or on N green runs of a
deterministic check while treating a judge-graded check the same way.
- Deleting, skipping, or overwriting-in-place the failing case instead of
fixing why it fails or superseding it with a new, versioned case.
- Loosening a threshold or assertion without a confidence-gated rationale
and a second independent check.
- Guessing the classification instead of reading the eval's own failure
output and logic — including checking `JUDGE_MODEL` before assuming a
code or eval regression.
- Continuing past 5 iterations because "just one more try."
- Reusing a different `RUN_CMD` between iterations, making runs
incomparable.
## Definition of Done
- [ ] Baseline failure (and `JUDGE_MODEL`, if judge-graded) captured from
an actual run, not assumed.
- [ ] `RUN_CMD` and `GRADING_PATH` resolved once and held constant across
iterations.
- [ ] Every iteration has an explicit verdict (Phase 2), including
`judge-drift` and an `eval-bug` subtype where applicable.
- [ ] Any eval-definition edit passed a second independent check plus the
`confidence(analysis) >= 90%` gate, is logged with its rationale,
and left the original case retained rather than overwritten.
- [ ] The eval passed **N consecutive times** (2 deterministic / 5 judge)
before being reported `confirmed-green`.
- [ ] The iteration cap (≤ 5, never raised) was respected.
- [ ] The structured report (Phase 6) was printed, regardless of outcome.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!