Repository navigation
Keep the qed_math_env answer-mode reference server-side and stop scoring after done in reasoning_gym_env and finqa_env - #1552
Open
jimmy-holdout wants to merge 3 commits into
Conversation
…gent
In answer mode, reset() put reference_solution (already wrapped as
\boxed{gold}) in the ProblemObservation, and the get_problem MCP tool added
it to its payload. Rows without a rubric are routed to answer mode
automatically. On HuggingFaceH4/MATH-500, submitting that reference
verbatim scored 1.0 on 391 of the 500 rows.
Grading already reads the reference from the server-side problem and the
gold cache, so both outputs now leave it out, as proof mode already did.
QED-Nano formats only the task into the actor prompt and passes the answer
to the verifier, so this does not change parity with it.
Signed-off-by: jimmy-holdout <346065422+jimmy-holdout@users.noreply.github.com>
step() returns done=True with correct_answer, but it kept the current entry, so a second step() on the same question was scored again. Answering anything, then answering the revealed correct_answer, scored 1.0. The harness forwards correct_answer to the agent in the tool result, and StepEnvSessionAdapter and SessionMCPBridge pass further calls through. The observation of the first scored answer is now kept, and later step() calls return it again until reset(), without scoring or counting a step. The episode reward stays the scored answer's reward, both for callers that read the last step (the session's default verify()) and for _resolve_env_reward. Signed-off-by: jimmy-holdout <346065422+jimmy-holdout@users.noreply.github.com>
submit_answer returned done=True with ground_truth in the metadata, but nothing recorded that the episode had ended. A second submit_answer was scored again, so submitting anything and then the returned ground_truth scored 1.0. The submit branch also runs before the max_steps check, so a submission after the episode had ended at max_steps was still scored. step() and step_async() now keep the terminal observation when an answer is submitted or max_steps is reached. Any later step returns it again until reset(): no tool runs, nothing is scored, and step_count does not change. A submission on the last allowed step is still scored. Signed-off-by: jimmy-holdout <346065422+jimmy-holdout@users.noreply.github.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1551
Summary
There are three commits, one per environment in the issue.
qed_math_envno longer sends the answer-mode reference solution to the agent.reasoning_gym_envandfinqa_envstop scoring once the episode has ended. Laterstep()calls return the episode's final observation again, with the same reward, untilreset().qed_math_env:reset()leavesProblemObservation.reference_solutionempty andget_problemleaves it out in both modes. Proof mode already worked this way. Grading still reads the reference from the server-side problem and the gold cache. The docstrings (the class,reset(),mcp_server.py), thereference_solutionfield description and the README now say the reference is not sent.reasoning_gym_env: the observation of the first scored answer is kept, and laterstep()calls return a copy of it untilreset(), without scoring or counting a step. The episode reward therefore stays the scored answer's reward. That holds for the session's defaultverify(), which reads the last step, for_resolve_env_reward, which reads the last non-Nonetool reward, and for any loop that reads the last step. The existing "no current entry" branch is unchanged.finqa_env:step()andstep_async()keep the terminal observation when an answer is submitted ormax_stepsis reached, andreset()clears it. Any later step, includingListToolsAction, returns a copy of it: no tool runs, nothing is scored, andstep_countdoes not change. A submission on the last allowed step is still scored.ground_truthstays in the submit observation, which now comes only at the end of the episode.Behaviour changes for callers:
reference_solutionfrom theqed_math_envreset observation or theget_problempayload in answer mode now gets""or no key.reasoning_gym_envandfinqa_env, astep()afterdonenow gets the final observation again instead of a new score or a tool result. This applies to thestep()/ WebSocket path. The production/mcproute calls tools directly and never issued a step reward.Type of Change
Alignment Checklist
Before submitting, verify:
PRINCIPLES.mdand this PR aligns with our principlesINVARIANTS.mdand no invariants are violatedlint.sh) and the tests, and addressed all issueslint.shstops at itsruff format --check src/ tests/ envs/step onmaintoo. It lists the same 47 files onmainand on this branch: 46 underenvs/andsrc/openenv/core/harness/README.md. Three of them are READMEs edited here (qed_math, reasoning_gym, finqa). In those, ruff flags code blocks that this PR does not change.usort checkreports only the two known files.ruff format --checkon the changed Python files, andruff check src/ tests/, pass.scripts/sync_env_docs.py --checkpasses. The three doc stubs were regenerated with--fix.RFC Status
Test Plan
New tests. The ones that check the fix fail on the parent commit and pass on their own commit (qed 2, reasoning_gym 2, finqa 6). The honest-path controls pass on both.
tests/envs/test_qed_math_environment.py:test_answer_mode_hides_reference_solution(reset observation andget_problem) andtest_auto_detected_answer_mode_hides_reference_solution(a row without a rubric). Control:test_answer_mode_correct_answer_still_scores(\boxed{4}still gets reward 1.0).test_answer_mode_includes_reference_solutionis replaced.tests/envs/test_reasoning_gym_environment.py: wrong, then the revealed answer keeps reward 0.0; correct, then an extra step keeps 1.0. Control:reset()scores the next question normally. This fileimportorskipsreasoning_gym, which the CI job does not install, so these tests run only wherereasoning-gymis installed.tests/envs/test_finqa_environment.py: newTestEpisodeEnd, with synthetic data likeTestResetSeed, so it runs in CI. Fix tests cover a submit after a submit, a submit aftermax_steps, and aListToolsActionafter a correct submit (reward stays 1.0 andstep_countis unchanged), each throughstep()andstep_async(). Controls: a submit on the last allowed step (1.0) andreset().Runs:
test.yml, run on a fresh clone with the CI job's extra packages plusreasoning-gym(Python 3.13): 4344 passed, 110 skipped on this branch, and 4331 passed, 110 skipped onmain. The touched test files: 153 passed for qed (5 integration tests deselected), 30 passed for reasoning_gym, and 79 passed, 16 skipped for finqa. With the downloaded FinQA data linked atenvs/finqa_env/data, all 95 finqa tests pass, including the existing data-dependentTestEnvironment.reasoning_gym_envandfinqa_envimages were also built from their Dockerfiles and gave the same rewards. The finqa image was driven with raw/wsmessages.mainget_problem""/ absent\boxed{66}/ wrong\boxed{-12345}step("x"), then the revealed answerverify()/ resolved reward)verify()/ resolved reward)submit_answer("0"), then the returnedground_truthFINQA_MAX_STEPS=3ended the episodeNote
Medium Risk
Changes evaluation and training reward semantics plus the qed_math observation/MCP contract; callers that relied on answer-mode references or post-done steps will see different behavior.
Overview
Fixes reward and leakage bugs across three environments (#1551).
qed_math_envno longer exposes the reference solution inreset(),ProblemObservation, orget_problem(including answer mode). The field stays empty and the MCP payload omits it; grading still uses the server-side problem and gold cache. Docs and model field descriptions match this contract.reasoning_gym_envandfinqa_envcache the terminal observation when the episode ends (first scored answer / single step, orsubmit_answer/FINQA_MAX_STEPS). Laterstep()/step_async()calls return a copy of that observation with the samedoneand reward, without running tools, incrementingstep_count, or rescoring—so harnesses that read the last step no longer get inflated rewards from a second submit or the revealed correct answer.Breaking for integrators: answer-mode
reference_solutionconsumers get""or no key; post-donestep()no longer produces new scores or tool results untilreset(). New tests cover these paths for all three envs.Reviewed by Cursor Bugbot for commit 9920bc0. Bugbot is set up for automated code reviews on this repo. Configure here.