Skip to content
MCP Five

The GateProject #325 / 51

Evals: the report card

Never assert on prose. Score a pass rate. Include a case where the right answer is nothing.

You changed the system prompt. Did it help?

Without evals the honest answer is "I tried it once and it looked fine" โ€” which is not engineering. It is hoping, with extra steps.

An eval is embarrassingly simple

A list of prompts, and what should happen for each.

"how many cookies are in the jar?"      -> cookie_jar { action: "look" }
"roll 3d20 then add that many cookies"  -> roll_dice, THEN cookie_jar add
"empty the jar completely"              -> a call the gate stops
"what is MCP, in one sentence?"         -> NOTHING AT ALL

Run them, count, get a number. Change something. Run again.

That's it. The machinery is trivial. The three rules below are the entire difficulty, and each one is the difference between a suite that helps and a suite that quietly lies to you.

Rule 1 โ€” Never assert on prose

Asserting on the answer text

"The jar has 78 cookies"

"There are 78 cookies!"

"78 ๐Ÿช"

One correct answer, three different strings. Your suite fails at random.

Asserting on the calls

cookie_jar { action: "look" }

Which tool, with what arguments.

Structured, stable, and it is the behaviour you actually care about.

Rule 2 โ€” Run each case several times and score a pass rate

The model is not deterministic.

A case that passes 60% of the time passes on the first try more often than not. One green tick is a coin flip you mistook for a measurement.

bash
npm run evals -- --attempts 3 --label "baseline"

Three attempts is the minimum that tells you anything. Six cases at three attempts is 18 data points, and the score is 18/18 or it isn't.

Rule 3 โ€” Include a case where the correct answer is calling nothing

This is the one everybody skips.

An agent that reaches for tools when it shouldn't is exactly as broken as one that doesn't reach when it should.

Slower, more expensive, and touching things it had no business touching. And you will never catch it by hand, because it looks like enthusiasm. The agent is clearly working hard. It called four tools. It seems great.

no-tools is the case name in project #3's suite: "what is MCP, in one sentence?" โ€” the right answer is a sentence, and zero tool calls.

It has to be able to fail

A suite that passes everything on its first run has told you nothing until you have watched it go red.

So the gate rules were deliberately sabotaged and the suite re-run:

npm run evals โ€” with the gate broken on purpose
  gate-fires               โœ—โœ—    0%  0/2

WHAT WENT WRONG
gate-fires  (0/2)
    expected: requests a destructive call that the host's gate stops
    actual:   no call was gated (called: cookiejar__cookie_jar)

SCORE: 0%   (0/2)
PREVIOUS: 100%   (18/18)  "baseline"
REGRESSED: -100 points

per case:
  gate-fires               100% ->   0%  (-100)

The six cases

CaseAsserts
look-onlyreads the jar, changes nothing
chain-dice-to-cookiesrolls, then adds that number โ€” the chaining demo
no-toolscalls nothing at all
gate-firesrequests something the host's gate stops
picks-right-cipherdisambiguates the two secret_code tools
reads-historyreaches for jar_history rather than guessing

Six cases, three attempts each, 18/18. And they survived contact: project #4 added a third MCP server, four new tools, a recursive loop and a rewritten persistence path, and re-ran this exact suite unchanged as a regression net.

terminal
  look-only  chain-dice-to-cookies  no-tools  gate-fires  picks-right-cipher  reads-history
SCORE: 100%   (18/18)

Where this goes

Project #5 notices that an eval case is a prompt (costs money) and a check (a pure function) โ€” and that project #3 already writes every loop event to Postgres.

So the checks can be re-run against stored traces for nothing. 13/13, $0.00. See The suite that costs nothing.