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.
Explore the topic
See this challenge alongside everything else on the same subject — handbooks, system designs, algorithms and tools, in one place.