Grader testing for RL environments

Find the answers your grader shouldn't accept.

falsepass calls an environment's own reward code on completions whose verdict is known in advance, and reports every disagreement: wrong answers that get paid, right answers that don't. No model, no rollouts, no GPU.

uvx falsepass demo
probe resultsreward · expected
completiongotwant
#### 421.01.0ok
The answer is definitely not 42.1.00false pass
\boxed{42 \text{ is wrong}}1.00false pass
A B C D E F G H I J1.00false pass
#### 42.0.01.0false fail
(empty)0.00ok
Illustrative rows. Each pattern was found in a public environment.

How it works

A grader is an assertion. falsepass tests it the way you'd test any assertion you didn't write: feed it inputs whose right verdict you already know.

01

Point it at an environment

A Hub environment, a local folder, an Inspect AI task or a HUD environment. It is installed in its own throw-away virtualenv, pinned to the versions it was built for.

falsepass init owner/environment
02

Probe the grader

The reference answer and harmless variations of it; empty, echoed, every-option, hedged and wrong answers; malformed output; repeats. A mutation search and a static scan of the reward source join in.

falsepass audit environment --search 120
03

Confirm, then fix

Every failing probe becomes a stand-alone repro that needs only the environment's own packages. Patch the grader and rerun it to see exactly which rows change.

falsepass repro environment --probe P5

What it keeps finding

Run on a few dozen public RL environments, the same handful of grader defects turned up again and again, across different authors.

Graders that count words

Free-form tasks scored by keywords. One generic text, sent for every task, beat the dataset's own reference answers.

return df # dropna fillna astype …

Rewards for the form

Format and reasoning terms that never look at the answer pay a wrong answer about a third of the maximum.

<think>…</think> \boxed{B} (wrong)

Strict and lenient in the wrong places

A trailing period scores zero; a denial with no answer marker at all scores full marks.

The answer is definitely not 42.

Denials inside the answer box

Normalisation built for units drops the text after a number, and only one side of an equation is compared.

\boxed{13 = 12}

Exceptions nobody sees

A reward term that raises on every call is caught, logged and recorded as zero. Runs finish with plausible numbers.

NameError: name 're' is not defined

Episodes that don't end

A game keeps answering after it's over, and the reward re-reads every message, so whoever keeps talking scores highest.

That was a great game!

Read the write-up: Your reward function is an assertion →

See it catch a planted defect

falsepass demo audits a toy environment whose grader pays when the answer appears anywhere in the reply. The static scan points at the line, and three probes confirm it from different sides.

Terminal recording: falsepass demo finds a planted grading defect

Works where your environment lives

Published or still in a local folder. Each framework is driven through its own code path, so what gets tested is the grader as it really runs.

verifiers · Environments Hub

The environment's rubric or taskset, all three API generations, single- and multi-turn, with scripted tool-use policies.

Inspect AI

The task's own solver chain with a scripted model in place of generate(), then its scorers.

HUD

The task template's grader, driven the way HUD's server drives it. Answer-free probes when no references exist.

Check every push

The GitHub Action fails the build when a known-bad answer earns reward, and puts the probe table in the job summary.

# .github/workflows/falsepass.yml
on: [push, pull_request]
jobs:
  falsepass:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: Super-Eric/falsepass@main
        with:
          path: .
          fail-on: "ceiling>0.1 errors>0"

Made to be called by agents

Every command is non-interactive and has a machine-readable form, so a coding agent can run a whole audit and hand you leads it has already reproduced.

MCP server

Scan, init, audit, results, repro and discover as tools, for any MCP client.

Agent skill

The full audit procedure, including how to tell a defect from a design choice.

JSON and exit codes

A compact results digest sized for a context window, CI gates, and llms.txt for the docs.

 

$ claude mcp add falsepass -- \
    uvx --from "falsepass[mcp]" falsepass mcp

› audit the grader of owner/environment

  falsepass_init   owner/environment
  falsepass_audit  environment  n=25
  false_pass_ceiling 1.0  via P5 shotgun/all_in_one_slot
  falsepass_repro  environment  probe=["P5"]
  … runs the repro twice, reads the reward code,
    reports the line and a suggested fix

An illustrative session. Any MCP client works the same way: setup for other clients →

Leads, not verdicts. A failing probe is a reason to read the reward code. A finding needs a repro that runs twice with identical output, the line that causes it, and a check of how many real tasks it affects. Strictness the prompt asks for, and graders that are exploitable on purpose, aren't bugs.

Used on a few dozen public environments. Fixes go to the maintainers first, as small pull requests.