What happens
One unresponsive endpoint in a sampled blind eval kills the entire run, and the in-progress episode with it.
InferenceClient.infer gives up after infer_timeout (180 s) and raises TimeoutError. Nothing between
there and the top catches it: it propagates out of harness.py:329 (actions = self._session(...)) through
World.run, every background process is torn down, the open episode is discarded, and the operator is back
at a shell prompt. Restarting costs another sync of the output directory plus a full warmup — around 15
minutes on 6 Aug — before the next episode can run.
This happened twice in a row on 6 Aug with gyros-nm-n60-50k (16:07 and 16:19, both dying ~184 s after the
endpoint was sampled). Two operator hours were spent on two crashes and no episodes. The other two endpoints
in the set were healthy the whole time and could have carried the round.
Why warmup doesn't catch it
SampledPolicy._get_keys (policy/base.py:264) reads every sub-policy's meta in parallel, and for a
RemotePolicy that opens a throwaway session and handshakes (policy/remote.py:113). So warmup does force
each server to answer ready.
But warmup never sends an observation. An endpoint that reports ready before its weights are usable
passes warmup and then stalls on the first real inference — which is exactly what both crashes looked like.
The throwaway session is also closed immediately after the handshake, so any per-connection warm state the
server built is dropped before the first episode opens its own session.
Scope
This is not specific to one endpoint. Every endpoint-side fault we have hit this month has been fatal to the
whole run:
- 6 Aug —
nm_n60_50k accepts the session, never answers the first inference. Run dies at 180 s. Twice.
- 3 Aug — a curie endpoint sent a 2525 KiB observation into Modal's 2 MiB per-message cap; the connection
closed mid-episode and the run died.
- 5 Aug — a subtler variant: episode 40 ran its full 145 s with no commands recorded at all (2.7 rad of
joint travel against 50–82 for a real episode). Nothing failed loudly, so the operator scored it a
legitimate zero and it counted against the endpoint that drew it.
So the class is: the harness treats any endpoint fault as fatal, except when it doesn't notice at all.
What "progress" should mean
Open for discussion — the shape matters more than the details:
- Quarantine rather than crash. On a timeout or connection error, drop that endpoint from the sampled
set for the rest of the run and carry on with the others. A round with two of three endpoints is worth far
more than no round.
- Retry once with a fresh session before quarantining, since a half-open socket is not the same as a
dead backend.
- Warm with a real inference. Send one observation per endpoint during warmup and exclude any endpoint
that fails or exceeds a budget. Problems then surface before the operator starts, not 40 minutes in.
- Mark the episode as a rig fault, not a policy result. The in-flight episode should be recorded as
discarded, and an episode with no commands (the 5 Aug case) should never reach the scoring UI as a normal
zero.
infer_timeout should be reachable from the CLI. production passes headers to each RemotePolicy
but not the timeout, so today adjusting it needs a code change.
Two constraints any design has to respect:
- The eval is blind. The operator must be told that an endpoint dropped out — otherwise they cannot
reason about a round that suddenly has two arms — but must not be told which one.
BalancedSampler counts per key. A key set that shrinks mid-run needs defined behaviour, or the
remaining endpoints' balance silently changes meaning.
Why it is worth doing now
The Runway rounds are becoming routine — four this week, new endpoints every few days, and the endpoints are
deployed by a team we don't control and cannot debug. Endpoints that are half-broken on arrival are the
normal case, not the exception, and each one currently costs an operator session.
Due: 2026-08-11
What happens
One unresponsive endpoint in a sampled blind eval kills the entire run, and the in-progress episode with it.
InferenceClient.infergives up afterinfer_timeout(180 s) and raisesTimeoutError. Nothing betweenthere and the top catches it: it propagates out of
harness.py:329(actions = self._session(...)) throughWorld.run, every background process is torn down, the open episode is discarded, and the operator is backat a shell prompt. Restarting costs another sync of the output directory plus a full warmup — around 15
minutes on 6 Aug — before the next episode can run.
This happened twice in a row on 6 Aug with
gyros-nm-n60-50k(16:07 and 16:19, both dying ~184 s after theendpoint was sampled). Two operator hours were spent on two crashes and no episodes. The other two endpoints
in the set were healthy the whole time and could have carried the round.
Why warmup doesn't catch it
SampledPolicy._get_keys(policy/base.py:264) reads every sub-policy's meta in parallel, and for aRemotePolicythat opens a throwaway session and handshakes (policy/remote.py:113). So warmup does forceeach server to answer
ready.But warmup never sends an observation. An endpoint that reports
readybefore its weights are usablepasses warmup and then stalls on the first real inference — which is exactly what both crashes looked like.
The throwaway session is also closed immediately after the handshake, so any per-connection warm state the
server built is dropped before the first episode opens its own session.
Scope
This is not specific to one endpoint. Every endpoint-side fault we have hit this month has been fatal to the
whole run:
nm_n60_50kaccepts the session, never answers the first inference. Run dies at 180 s. Twice.closed mid-episode and the run died.
joint travel against 50–82 for a real episode). Nothing failed loudly, so the operator scored it a
legitimate zero and it counted against the endpoint that drew it.
So the class is: the harness treats any endpoint fault as fatal, except when it doesn't notice at all.
What "progress" should mean
Open for discussion — the shape matters more than the details:
set for the rest of the run and carry on with the others. A round with two of three endpoints is worth far
more than no round.
dead backend.
that fails or exceeds a budget. Problems then surface before the operator starts, not 40 minutes in.
discarded, and an episode with no commands (the 5 Aug case) should never reach the scoring UI as a normal
zero.
infer_timeoutshould be reachable from the CLI.productionpassesheadersto eachRemotePolicybut not the timeout, so today adjusting it needs a code change.
Two constraints any design has to respect:
reason about a round that suddenly has two arms — but must not be told which one.
BalancedSamplercounts per key. A key set that shrinks mid-run needs defined behaviour, or theremaining endpoints' balance silently changes meaning.
Why it is worth doing now
The Runway rounds are becoming routine — four this week, new endpoints every few days, and the endpoints are
deployed by a team we don't control and cannot debug. Endpoints that are half-broken on arrival are the
normal case, not the exception, and each one currently costs an operator session.
Due: 2026-08-11