From 335880bc7578b71996dcb470908f5a2e9b77796c Mon Sep 17 00:00:00 2001 From: hallerite Date: Wed, 7 Oct 2026 19:15:10 -0700 Subject: [PATCH] fix: retain explicitly scored execution timeouts in training --- src/prime_rl/orchestrator/dispatcher.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/prime_rl/orchestrator/dispatcher.py b/src/prime_rl/orchestrator/dispatcher.py index b9410915cea..a55d7218cfc 100644 --- a/src/prime_rl/orchestrator/dispatcher.py +++ b/src/prime_rl/orchestrator/dispatcher.py @@ -670,9 +670,15 @@ async def handle_completed_request(self, task: asyncio.Task) -> None: episode.errors.append(vf.Error(type="EmptyEpisode", message="Episode returned with no traces")) for trace in episode.traces: - if trace.is_timeout and not trace.has_error and meta.kind == "train": - # Training keeps a timed-out rollout out of the batch: an error, - # like any other failure. Eval keeps it as a scored outcome. + termination = getattr(trace, "termination", None) + scored_termination = ( + getattr(termination, "valid_sample", False) + and getattr(termination, "reward", None) is not None + and trace.reward == termination.reward + ) + if trace.is_timeout and not trace.has_error and meta.kind == "train" and not scored_termination: + # An explicit execution policy may retain a timeout as a scored + # training sample. Unclassified timeouts remain errors. trace.errors.append(vf.Error(type="Timeout", message=f"Trace stopped by {trace.stop_condition}")) trace.ok = False episode.ok = False