Harness and Verification

The sandbox where Champ agents are put under test, the specification a test scenario has to satisfy, and the rules that decide whether an agent is fit to deploy and still fit six months later.

Agent Architecture → System Internals → Event Log → Why a Harness Scenario Anatomy Sandbox Contract The Verifier Calibration Behaviour Probes Fairness Lines Release Gates Standing Audit How Scenarios Go Wrong
Why a Harness

An agent that reports "done" has told you about its confidence, not about its work. The harness exists to replace that self-report with evidence produced by something the agent does not control.

What the harness is

A containerised environment plus a grader. An agent is dropped into a sealed Linux sandbox with a written brief and a time budget, it works, and then a separate program inspects the artefacts it left behind and returns a single number: pass or fail.

  • The agent never sees the grader.
  • The grader never asks the agent how it went.
  • The same scenario, run a year later, produces the same environment byte for byte.

What it is not

  • Not a demo. A scenario that every model passes measures nothing and earns no place in the suite.
  • Not a chat transcript review. Reasoning that sounds right and output that is right are different claims, and only the second one is graded.
  • Not a one-off. A single pass can be luck. Scenarios are run repeatedly and scored across trials.
  • Not retired at launch. The same suite runs on a schedule after deployment as the audit.

The two things every run separates

Capability

Can the agent produce the correct artefact at all? Graded by assertions on real values in real files. Binary, and deliberately unforgiving.

Behaviour

How did it get there? Did it accept an authoritative-sounding tool at face value, assume an ordering nobody stated, or stop at the first plausible answer? Graded by scenarios built to reward exactly those shortcuts with a wrong answer that looks normal.

Anatomy of a Scenario

A scenario is a folder, and the folder is the specification. Five parts, each with one job. The layout follows the Terminal-Bench 2 and Harbor convention so scenarios stay portable to any harness that speaks it.

scenario/
  ├── task.toml           # the manifest: artefact paths, resource limits, timeouts, metadata
  ├── instruction.md       # the brief handed verbatim to the agent, and the only thing it sees
  ├── environment/
  │   ├── Dockerfile      # the single image, pinned by digest, used for both the run and the grade
  │   └── data/          # seed inputs copied into the image at build time
  ├── tests/             # the verifier, overlaid only after the agent has finished
  │   ├── test.sh        # runs the assertions, writes reward.txt and ctrf.json
  │   └── test_outputs.py  # one assertion per stated success criterion
  └── solution/
      └── solve.sh        # the reference answer, never copied into the image

What each part is responsible for

PartResponsibilityRule it must not break
instruction.md The brief, written the way you would brief a colleague. Absolute output paths, the exact format, numbered success criteria, the "what" and never the "how". No section headers, no solution hints, and a hard cap of roughly 1,500 tokens. If it does not fit, the scenario is doing too much.
task.toml The manifest. Declared artefact paths, CPU, memory, storage, GPU, internet access, MCP servers, agent timeout, verifier timeout, and the metadata that classifies the scenario. artifacts is an array at the top level and names the exact file the scenario produces.
environment/Dockerfile The starting state, and nothing more. Runtimes, libraries, seed data, and the pinned test dependencies baked in ahead of time. Never copies solution/ or tests/. An image containing either is rejected outright.
tests/ The verifier. One test function per success criterion, each carrying a docstring naming the criterion it covers. Added only at verify time. Ground truth lives here, never in environment/ where the agent could read it.
solution/solve.sh The reference answer, used to prove the grader is capable of recognising a correct result. Exists for calibration and review only. It is never present during an agent run.
Four-way consistency The output path in instruction.md, the artifacts entry in task.toml, the path the verifier asserts on, and the path solve.sh writes to must all be the same file. Drift between any two of them is the most common way a scenario becomes quietly unfair.
The Sandbox Contract

The environment has to be honest and it has to be reproducible. Honest means the answer is not sitting somewhere the agent can find it. Reproducible means a result from today can be compared against a result from next year without an argument about whether the ground moved.

Reproducible

  • The base image is pinned by @sha256 digest, not by tag. A tag like python:3.13-slim silently changes underneath you, and :latest is never allowed.
  • Base images come from a fixed approved list, so the fleet shares a known surface.
  • Every dependency, including the test dependencies, is installed at build time with a pinned version. Grading downloads nothing.
  • Tests use fixed seeds and fixed inputs. No unseeded randomness, no live-generated data, no dependence on the wall clock or the date.

Honest

  • No answer file, reference solution, or expected output anywhere in the image.
  • The verifier is absent during the run and overlaid afterwards, so there is nothing to read ahead.
  • Ground truth is either held in the verifier's own copy or recomputed from inputs the agent cannot write.
  • Where the scenario allows network access, it is designed so the answer cannot simply be fetched.

Post-build leak check

Run after every image build. Any output at all is a failing scenario.

# nothing from solution/ or tests/ may exist inside the agent image
docker run --rm <scenario>:dev /bin/bash -lc \
  'find / \( -name solve.sh -o -name test.sh -o -name "*expected*" \) 2>/dev/null'

# expect: no output

Environment budget, declared in task.toml

FieldWhat it controlsWhy it is pinned
cpus / memory_mb / storage_mbThe compute the agent is given.A result is only comparable against another result run under the same budget.
gpusAccelerator access, normally zero.Keeps runs schedulable and keeps cost predictable.
allow_internetWhether the sandbox can reach the network.Off by default for anything where a lookup would substitute for the reasoning under test.
mcp_serversWhich tools the agent is handed.The tool surface is part of the test. Some behaviour probes work precisely by offering a tool that should not be trusted.
[agent].timeout_secThe working budget.Timeouts are recorded separately from wrong answers, because they measure a different thing.
[environment].build_timeout_secImage build ceiling.A scenario that cannot build in budget cannot run at scale.
[verifier].timeout_secGrading budget.The verifier runs in a fresh container from the same image, so its cost is bounded too.
The Verifier

A weak verifier is worse than no verifier, because it produces a number people trust. The rule is that the grader checks the real outcome, not the appearance of one.

Weak

def test_report():
    """A report was produced."""
    assert Path("/app/report.json").exists()

An agent that writes {} and stops passes this. So does an agent that writes an empty file and reports success. The number this produces is not a measurement.

Sound

def test_duplicate_accounting():
    """Criterion 3: duplicates_removed equals
    input_rows minus output_rows."""
    d = json.loads(Path("/app/report.json").read_text())
    assert d["input_rows"] == 14032
    assert d["output_rows"] == 13887
    assert d["duplicates_removed"] == 145

Asserts on produced values, names the criterion it covers, and cannot be satisfied without doing the work.

Rules the verifier holds to

  • One test function per stated success criterion, each with a docstring naming it.
  • Tests map to criteria one to one. Nothing graded that was not asked, nothing asked that is not graded.
  • Assertions run against observable artefacts at the declared paths, never against stdout and never by string-matching the agent's source.
  • test.sh installs nothing and downloads nothing. Dependencies were baked in at build.
  • test.sh always exits zero and always writes a reward, including on missing prerequisites, so a crashed grader cannot be mistaken for a pass.
  • The reward lands in /logs/verifier/reward.txt and the per-test detail in ctrf.json.
#!/bin/bash
pytest --ctrf /logs/verifier/ctrf.json /tests/test_outputs.py -rA

if [ $? -eq 0 ]; then
  echo 1 > /logs/verifier/reward.txt
else
  echo 0 > /logs/verifier/reward.txt
fi
The misalignment failure A verifier that checks a format, an ordering, or a tie-break the brief never stated is the single largest source of rejected scenarios. It produces failures that look like agent weakness and are actually author error. Any failure traced to misalignment is treated as blocking: the scenario is fixed before any result from it is quoted.

The second verifier: in-flight checks on live work

The scenario verifier grades an agent offline. Inside a running swarm the same discipline applies to every work packet, through a typed verification spec that Champ executes in the VERIFYING phase.

What a packet declares

interface VerificationSpec {
  checks: Array<{
    type: "test" | "typecheck" | "lint"
        | "build" | "runtime"
        | "security" | "performance";
    command: string;
    required: boolean;
  }>;
}

Each check is a real command run in the packet's working directory. The agent's own account of its work is not an input.

What comes back

interface VerificationResult {
  passed: boolean;      // every required check passed
  evidence: VerificationEvidence[];
  confidence: "high" | "medium" | "low";
  summary: string;
}

Evidence carries the command, the captured output, and the duration for every check, so a pass can be re-read later rather than taken on trust.

Confidence, and why a failed check is not the same as a check that never ran

ConfidenceConditionWhat it means for the result
highEvery check executed, whether or not it passed.The verdict stands on complete evidence. A failure here is a real failure.
mediumOne or more optional checks failed to spawn.The verdict holds, with a known gap in the supporting evidence.
lowA required check failed to spawn at all.Critical evidence is missing. A pass here is not a pass, it is an absence of information, and the fix loop treats it accordingly.
Calibration: Proving the Harness Before Trusting It

Before a scenario is allowed to say anything about an agent, it has to say the right thing about two agents whose answers are already known.

Oracle must pass

Run the harness with the oracle agent, which does nothing but execute the reference solution. Reward must be exactly 1.0.

harbor run -p . --agent oracle
cat /logs/verifier/reward.txt   # expect 1.0

If the oracle fails, the scenario is unsolvable as written or the verifier is checking something the brief never asked for.

Nop must fail

Run it again with the nop agent, which does absolutely nothing. Reward must be below 1.0.

harbor run -p . --agent nop
cat /logs/verifier/reward.txt   # expect < 1.0

If nop passes, the verifier is scoring a result that was never produced. Tighten the assertions until doing nothing fails.

The third check: a deliberately wrong solution

Replace the reference solution with a stub, re-run, and confirm the reward drops. This catches the verifier that passes anything with the right file shape.

echo '#!/bin/bash' > solution/solve.sh
harbor run -p . --agent oracle       # expect < 1.0

git checkout solution/solve.sh
harbor run -p . --agent oracle       # expect 1.0
The calibration rule The harness is correct if and only if it fails a wrong solution and passes the golden one. Until both hold, any score it produces about a real agent is noise.
Behaviour Probes

Correctness scenarios ask whether an agent can do the work. Behaviour probes ask what it does when the obvious route is wrong. Each probe is built around a specific shortcut, and each one is designed so that taking the shortcut produces an answer that looks entirely normal.

Probe
Latent variable

Every example the agent has seen varies along the same axes, so it learns to price a part from size, thickness and geometry. Then it is handed a drawing of a part that is not steel. Material was never a column in anything it saw, so it answers confidently and wrongly.

Passes when the agent notices that a determining variable is absent from its evidence and says so, rather than extrapolating past the edge of what it was given.
Probe
Misdirection by authoritative tool

The scenario is a subsystem failure, and the environment helpfully includes a diagnostic tool. The tool reports the downstream component that tripped. Reading the tool and reporting its answer is the shortest path to something that reads like a root cause.

Passes when the agent treats the tool as one downstream signal, keeps tracing upstream, and reaches the cause the tool cannot see. Eagerness to finish is the thing under test.
Probe
Ordering assumption

Encoded records carry a position and a timestamp. One record sits far outside the sequence. An agent that assumes the file is ordered will extract in file order and build the whole result on that assumption.

Passes when the agent establishes its own scale from the timestamps and places each point independently, instead of inheriting an order nobody stated.
Probe
Rollup double-count

A cost hierarchy where children roll up into parents, except that parents also carry costs of their own. Summing children into the parent total is the natural move and it double-counts, quietly, in a report that balances at every other level.

Passes when the agent separates own-cost from rolled-up cost before aggregating, and can show the reconciliation.

Amplifiers

Three dials that make a probe bite harder. They are applied deliberately, and only as far as the fairness lines allow.

Silent failure

The wrong answer looks normal. No crash, no error, no signal to keep going. An agent that hits an exception keeps working on it; an agent that gets a plausible number stops. Every wrong path is engineered to be a believable near-miss.

No self-check

The visible sample is friendly and unrepresentative. Grading runs on held-out cases the agent never sees, so matching the sample only feels like success.

All or nothing

No partial credit. One wrong component fails the whole result. Used only where the deliverable genuinely is a single correct artefact, not where partial progress should count.

Fairness Lines

A probe should be hard because it demands skill, not because it is impossible or because it turns on a coin flip. Four lines keep it honest.

Figure-out-able

The answer is recoverable from what the agent is given. Nothing decisive is secret.

Real skill

It punishes a mistake a competent practitioner would avoid, not a random trick.

Fair margins

Pass and fail do not hinge on a hair-thin tolerance. The idea decides the outcome, not the threshold.

No uncorrectable lie

Hiding the deciding case is fair. Stating a wrong rule that nothing in the scenario can set straight is not.

The gut check Would a competent human expert, seeing only what the agent sees, get it right, and would they call the failure fair? Yes to both means the probe is sound. If the expert would also be stuck, the probe is measuring luck and is cut.
Release Gates: Before an Agent Is Deployed

Scenarios are graded in two passes, for two different purposes. The first asks whether the scenario is worth keeping. The second asks whether the agent is fit to ship.

Pass 1, calibrating the scenario

A scenario earns a place in the suite only if it discriminates. Run it against a current frontier model at high reasoning effort:

  • Stage one, two trials. At least one genuine failure, or the scenario is not measuring anything and is retired to the regression set.
  • Stage two, eight fresh trials. Triggered only if stage one clears. At least four genuine failures out of eight.

Only genuine failures count. Timeouts, infrastructure faults and misalignment between the brief and the verifier are excluded, and misalignment is blocking: it is fixed before the scenario runs again.

Pass 2, grading the agent

The calibrated suite is then run against the candidate agent, multiple trials per scenario, and reported as a distribution rather than a single verdict:

  • Pass rate per scenario across trials, because one pass can be luck and one failure can be a bad draw.
  • Consistency, how often the same scenario produces the same outcome. An agent that alternates is not ready even if its average looks acceptable.
  • Cost and wall clock per scenario, tracked as first-class results.
  • Failure class, separating wrong answers from timeouts, tool errors and refusals.

What has to be true before the agent goes live

Capability floor The agent clears the correctness suite for the role it is being deployed into, at the declared pass rate, across repeated trials rather than one lucky run. blocking
Behaviour floor No unhandled failure on the probe set for the shortcuts that matter in its domain. A capable agent that takes the authoritative tool at face value is not deployable into an operations role. blocking
No regression Compared against the previous deployed baseline on the frozen suite. A scenario that used to pass and now fails blocks the release regardless of the overall average. blocking
Evidence confidence Every result carries high confidence. A required check that failed to spawn means the run is repeated, not interpreted. blocking
Budget Cost and latency per scenario are within the envelope the deployment was sized for. A rising cost curve on unchanged scenarios is treated as a defect. advisory
Recorded baseline The suite version, image digests, model identifier, and full result set are stored together as the reference the next audit compares against. required
Standing Audit: After an Agent Is Deployed

Nothing about a deployed agent is static. The model behind it gets updated, the tools it calls change shape, and the work it is asked to do drifts away from what it was tested on. The audit exists because a release gate is a photograph and production is a film.

The audit loop

Re-run frozen suite Same scenarios, same pinned images, same seeds, compared line by line against the recorded baseline.
Replay production traces Real work the agent handled, replayed in the sandbox where the outcome can be graded without touching anything live.
Diff against baseline Pass rate, consistency, cost, latency, and failure class. Any scenario that flipped is investigated individually.
Promote new failures Every production failure worth the name becomes a new scenario, so the same fault can never regress unnoticed twice.

What triggers an audit

TriggerScopeTypical cadence
ScheduledFull frozen suite plus the probe set.monthly
Model changeFull suite. A provider-side model update is treated as a new agent, not as maintenance.before cutover
Prompt or skill changeThe affected role's suite plus the regression set.per change
Tool or MCP surface changeEvery scenario whose manifest lists the affected server.per change
Production signalTargeted replay. Rising retries, overrides, abandonment, cost per task, or tool error rate are all quality signals.on alert
IncidentTrace replay, then a new scenario built from the failure before the fix is accepted.immediate

Signals watched between audits

  • Success rate per task type, with a threshold that raises an alert rather than waiting for the next scheduled run.
  • Cost per task over time. A climbing curve on unchanged work usually means prompt or context drift.
  • Tool error rates, which catch breaking changes on the other side of an integration.
  • Human override and retry rates, which catch the failures the verifier was never written to see.

What the audit record holds

  • Suite version and the image digest for every scenario, so the run can be reproduced exactly.
  • Model and agent identifiers, and the resource budget each scenario ran under.
  • Per-scenario reward, per-check evidence, confidence, and duration.
  • The diff against the previous baseline, and the disposition of every changed line.
Why the frozen suite matters An audit is only meaningful if the thing being re-run has not changed. Scenarios are versioned and their images are pinned by digest, so a difference between this month and last month is a difference in the agent. If the suite needs to change, it is versioned forward and the baseline is re-established rather than quietly edited.
How Scenarios Go Wrong

Nearly every scenario that gets thrown out fails for one of five reasons. In each case it looked hard, and the agent failed because something was unfair rather than because the problem was genuinely difficult.

1. Grading on a rule nobody stated

The verifier checks a format, an ordering, or a tie-break the brief never mentioned. This is roughly half of all rejections on its own, and it is the reason the one-to-one mapping between criteria and tests is enforced rather than encouraged.

2. Files that contradict the brief

A data file or the reference solution follows a different rule from the instruction. The agent reads the environment correctly and is marked wrong for it.

3. A brief that reads two ways

Both readings are defensible and the grader silently accepts one. This measures the author's phrasing, not the agent.

4. The only hard part is a mistake

The difficulty comes entirely from an error in the scenario. Disclose it or fix it honestly and the task becomes trivial, which tells you it was never a test of anything.

5. A decoy with no way out

The scenario points at the wrong answer and gives the agent nothing it could use to correct course. That is not a probe, it is a trap with no skill in it.

The test to apply before shipping a scenario

Write the deciding rule down plainly and add it to the brief. If the scenario becomes easy, the difficulty was fake and the scenario goes back for rework. A sound scenario stays hard even when every rule is stated clearly.

Plain-Language Key
TermWhat it means
HarnessThe machinery that builds the sandbox, runs the agent inside it, runs the grader afterwards, and records the result.
ScenarioOne self-contained test: a brief, an environment, a grader, and a reference answer.
Trial or runOne independent attempt at a scenario. Scenarios are attempted several times because a single result is not a measurement.
VerifierThe program that decides pass or fail by inspecting what the agent produced.
RewardThe verifier's output. 1 for pass, 0 for fail, written to /logs/verifier/reward.txt.
OracleA stand-in agent that just runs the reference solution. Used to prove the scenario is solvable.
NopA stand-in agent that does nothing. Used to prove the grader cannot be passed by inaction.
Held-outTest inputs used only for grading, never shown to the agent while it works.
Pass@kShorthand for how many times a scenario was attempted and how it went. "4 of 8 fail" means it was wrong on four of eight independent attempts.
ProbeA scenario built around a specific shortcut, where taking the shortcut yields a wrong answer that looks normal.
BaselineThe recorded result set from the last accepted release, and the thing every audit is compared against.
Frozen suiteA versioned set of scenarios with pinned images, held constant so that a change in results means a change in the agent.
Champ Agent Swarm, Harness and Verification. ← Champ Agent Swarm index