fix(v1): cancel the sibling scorer when one scoring handler fails#2074
Closed
dumko2001 wants to merge 3 commits into
Closed
fix(v1): cancel the sibling scorer when one scoring handler fails#2074dumko2001 wants to merge 3 commits into
dumko2001 wants to merge 3 commits into
Conversation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
dumko2001
marked this pull request as ready for review
July 20, 2026 08:54
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7bb5d4f. Configure here.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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.

Description
When one scorer failed, the other kept running and could keep writing to a trace that was already being torn down.
Rolloutscores a trace by awaiting the task scorer and the harness scorer together with a bareasyncio.gather.gatherpropagates the first exception right away, but it does not cancel the sibling. That sibling keeps mutating the trace, calling judges, and using a runtime the failure path is already shutting down, which can corrupt the trace or raise confusing follow-on errors.The fix routes both scorers through a
gather_scoringhelper. It runs them as explicit tasks, shields them while active, and on any failure cancels the unfinished siblings and drains them before propagating. The original failure wins over errors raised during cleanup, and a caller cancellation that arrives during cleanup stays the final outcome. Result ordering is unchanged.Type of Change
Testing
uv run pytestlocally.Verified with a local script covering single failure, timeout, simultaneous failures, repeated cancellation, cleanup raising, empty and singleton call sets, preserved ordering, and no leaked tasks.
uv run pytest tests/v1/— 63 passed, 144 skipped (requirePRIME_API_KEY).uv run ruff check .andruff format --check .clean.Checklist
Additional Notes
Open #2067 edits this exact scoring block and #1939 replaces
Rollout; both keep rawgather. The helper is independent and its call site rebases cleanly onto either.Note
Cancel sibling scorer when one scoring handler fails in v1 rollout
gather_scoringin rollout.py, an async helper that runs multiple scoring awaitables concurrently, each wrapped withasyncio.shieldto prevent premature cancellation by an outer timeout.gather_scoringcancels all remaining sibling tasks and drains them viaasyncio.gather(..., return_exceptions=True)before re-raising the original error.asyncio.gatherin the scoring phase withgather_scoringso a failure in one scorer reliably cancels and drains the other.Macroscope summarized 3e9bb05.
Note
Medium Risk
Touches concurrent scoring on every rollout teardown path; behavior change is localized to failure/cancellation cleanup but errors in the new helper could affect how scoring failures propagate.
Overview
Fixes a concurrency bug in
Rollout’s scoring phase: when one of the two concurrent scorers (task.scoreandharness.score) failed, a plainasyncio.gatherreturned immediately while the other kept running and could keep writing to the trace or using a runtime already being torn down.The PR introduces
gather_scoringinrollout.py, which runs scoring awaitables as explicit tasks (with per-taskasyncio.shieldwhile gathering), and on any failure cancels unfinished siblings and drains them viarun_shieldedbefore re-raising the original error. The scoringwait_forblock now callsgather_scoring(...)instead ofasyncio.gather(...); result ordering and the outer scoring timeout behavior stay the same.Reviewed by Cursor Bugbot for commit 3e9bb05. Bugbot is set up for automated code reviews on this repo. Configure here.