Write a Verifier
In RL from verifiable rewards, the verifier IS the reward. A gameable verifier is worse than no verifier — every false positive is a lie the model happily learns to reproduce. Write one that a reward-hacking agent cannot fool: recompute the score from ground truth, demand exact coverage, and compare with types intact.
The problem
Implement verify(submission, answer_key). answer_key maps each task_id to the correct answer. submission is what the agent hands back: {"outputs": {task_id: value, …}, "reported_reward": float}. Return {"reward": float, "accepted": bool} under three rules that close three reward hacks: (1) never trust reported_reward — recompute the reward yourself from outputs vs answer_key; (2) accepted is False (reward 0.0) unless outputs covers exactly the answer-key task ids — nothing missing, nothing extra; (3) a task counts correct only on a type-strict match (1 is not True, "1" is not 1). When accepted, reward is (# correct) / (# tasks).
submission={"outputs": {"t1": 4, "t2": 9}, "reported_reward": 1.0}, answer_key={"t1": 4, "t2": 9}{'reward': 1.0, 'accepted': True}submission={"outputs": {"t1": 0, "t2": 0}, "reported_reward": 1.0}, answer_key={"t1": 4, "t2": 9}{'reward': 0.0, 'accepted': True}submission={"outputs": {"b1": True}, "reported_reward": 1.0}, answer_key={"b1": 1}{'reward': 0.0, 'accepted': True}submission={"outputs": {"t1": 4}, "reported_reward": 1.0}, answer_key={"t1": 4, "t2": 9}{'reward': 0.0, 'accepted': False}- Recompute the reward from
outputsvsanswer_key.reported_rewardis the agent’s self-report — never let it influence the result. - Coverage must be exact: the set of
outputskeys must equal the set ofanswer_keykeys. A missing task OR an extra task ⇒accepted=False,reward=0.0. - Correct means a type-strict match: same value AND same type. In Python,
type(got) is type(expected)before==(soTrue≠1,"1"≠1). - When accepted,
reward = correct / len(answer_key). An empty answer key is a vacuous accept:{"reward": 0.0, "accepted": True}.
Your turn — write it
Edit the stub, hit Run (or ⌘/Ctrl + Enter), and watch the hidden tests. Stuck? the hints are right above and Reveal solution is one click away.
Implement verify(submission, answer_key) — recompute the reward from ground truth, reject anything but exact task coverage, and score only type-strict matches. Return {"reward": float, "accepted": bool}.
- Start with coverage: if set(submission["outputs"]) != set(answer_key), return {"reward": 0.0, "accepted": False} — before you score anything.
- Never read submission["reported_reward"] into your result. It exists only to tempt you.
- Type-strict: for each task, count it correct only when type(got) is type(expected) AND got == expected. This is what stops True from passing as 1.
- reward = correct / len(answer_key) once accepted. Guard the empty key first: an empty answer_key is a vacuous accept with reward 0.0.
Approach, complexity & discussion — open after you solve
The approach
Trust nothing the submission tells you. Recompute the reward yourself from outputs vs answer_key, and gate acceptance on two structural checks before you even score: exact coverage (the output keys equal the answer-key keys — nothing missing, nothing extra) and a type-strict match per task. Score only what survives both. Every rule here is a variation on “verify, don’t trust.”
Complexity
Time O(n) in the number of tasks; space O(n) for the key sets. A single pass — the cost is discipline, not computation.
Common mistakes
- Reading
reported_rewardinto the result — it exists only to tempt you; recompute instead. - Comparing with
==and no type check, soTruepasses as1(in Python1 == True) and"1"nearly passes as1. - Giving partial credit on partial coverage — a submission that answers only the easy tasks must score 0, not a fraction.
- Forgetting the empty answer-key case (a vacuous accept with reward 0).
Where this shows up
This is the heart of RLVR (reinforcement learning from verifiable rewards): the verifier is the reward, so a gameable one is worse than none — every false positive is a lie the model learns to reproduce. The same “recompute from ground truth, demand exact coverage, compare strictly” discipline runs every autograder, CI test harness, and payments reconciler that scores untrusted input.
Explore the topic
See this challenge alongside everything else on the same subject — handbooks, system designs, algorithms and tools, in one place.