Repository navigation
Conversation
This was referenced Oct 13, 2026
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
2 times, most recently
from
October 14, 2026 15:30
63e4000 to
1c74051
Compare
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
from
October 14, 2026 17:24
1c74051 to
d01e2bf
Compare
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
from
October 14, 2026 19:19
d01e2bf to
15da4b5
Compare
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
from
October 14, 2026 19:46
15da4b5 to
f763b3b
Compare
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
from
October 15, 2026 01:10
f763b3b to
8628477
Compare
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
from
October 15, 2026 19:48
8628477 to
d14946d
Compare
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
2 times, most recently
from
October 15, 2026 20:30
727ab37 to
ace647e
Compare
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
from
October 16, 2026 08:40
75ab669 to
d653a41
Compare
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
from
October 17, 2026 01:44
d653a41 to
6194514
Compare
This was referenced Oct 20, 2026
Draft
pthombre
marked this pull request as ready for review
October 20, 2026 17:13
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
from
October 21, 2026 03:04
6194514 to
e3d44dd
Compare
This was referenced Oct 22, 2026
7 tasks done
…heckpoints Snapshot at commit, fork at restore, on_stop kill by default. Snapshots are indexed under `checkpoint.state_dir` by checkpoint and deleted when the controller releases the checkpoints that name them, also by a restarted server that has not created a sandbox yet; verify only stops the sandbox. With checkpointing on, the server refuses to start without `checkpoint.state_dir`. Signed-off-by: Pranav Prashant Thombre <pthombre@nvidia.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eplacement's rollout prefix The base refuses a cookie-only call to a restored resources session; the replacement's calls carry its /ng-rollout prefix. Signed-off-by: Pranav Prashant Thombre <pthombre@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A /verify for a session whose sandbox is gone, such as a resend after the first verify graded and stopped it, extracted no patch and graded the empty one as reward 0. It now answers 409 before it starts a grading sandbox, as it failed before the sandbox moved into the checkpointer. Signed-off-by: Pranav Prashant Thombre <pthombre@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ourcesServer The SWE-bench server and the e2e sandbox notes server each wired the same pieces by hand: the shared provider, the SandboxSessionCheckpointer, the checkpoint hooks (export, restore, retire, park, release), the workdirs and /sandbox_access. nemo_gym/sandbox/owner.py now writes them once. A subclass starts the session's sandbox at seed with start_session_sandbox, reuses session_sandbox when a replacement re-seeds a restored session, answers 409 through require_session_sandbox, and ends the session with end_session_sandbox. SandboxCheckpointConfig moves to nemo_gym/sandbox/checkpoint.py. Behaviour is unchanged; the tests change only where they patch the provider resolution, which moved into the base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Pranav Prashant Thombre <pthombre@nvidia.com>
… captured The owner base now gets right what each sandbox-owning server would otherwise get wrong on its own: - Setup before tracking. start_session_sandbox runs the setup, then tracks the sandbox; a setup that raises stops it and leaves nothing to export. SWE-bench's anti-cheat moves into the setup: it used to run after the sandbox was tracked, so a failed seed leaked a tracked sandbox. - Snapshot-only checkpointing. Only a provider that can snapshot can checkpoint a session; on docker, apptainer or enroot every commit with a session in flight failed. With checkpointing on, the server builds its provider at startup and runs restart_only, with one warning, when the provider cannot snapshot: its rollouts restart after a crash instead of continuing. The mode comes from a new SimpleResourcesServer hook, checkpoint_mode_in_effect(), whose default is the declared checkpoint_mode. - Instances that lend no sandbox. lends_sandboxes() (default True) false means restart_only, with no provider, state_dir or worker check. SWE-bench's golden-patch instance only grades and runs 8 workers; training configs load it with the agent-facing instance, so it must not block startup. - The worker guard. Release and park do not reach the workers of a multi-worker server yet, so a server that checkpoints its sandboxes refuses to start with num_workers > 1. - Per-session data. A setup may return a small JSON object (SessionData), such as the commit the agent started from; the base exports it next to the snapshot, restores it all or nothing with the sandbox, and drops it when the session ends. session_data() reads it. The e2e notes server returns a seed token and rewards nothing without it, so its crash scenarios prove the data survives a process-level restore. - /close_session with an empty body ends the cookie's session, for an agent that leaves without a verdict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Pranav Prashant Thombre <pthombre@nvidia.com>
pthombre
force-pushed
the
pthombre/partial-ckpt-sandbox-swebench
branch
from
October 25, 2026 02:47
e3d44dd to
7d573d7
Compare
8 tasks
7 tasks done
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.
What changed and why
A resources server that owns one sandbox per session and lends it to the agent, as SWE-bench does, needs the same checkpoint wiring every time: a shared provider, a
SandboxSessionCheckpointer(#4220), the export/restore/retire/park/release hooks, the working directory,/sandbox_access, and a 409 instead of grading an empty patch. This PR writes that once, asSandboxOwnerResourcesServer(nemo_gym/sandbox/owner.py), and moves the SWE-bench server and the e2esandbox_notes_serveronto it. The base also gets right what each such server would otherwise get wrong on its own.The owner base. A subclass starts the session's sandbox at seed and ends it when it is done with it:
start_session_sandbox(session_id, spec, *, setup=None, workdir=None)starts the sandbox on the shared provider, runssetupagainst it, and only then tracks it. A setup that raises stops the sandbox and leaves nothing for a checkpoint to export. The working directory defaults topwdafter the setup.session_sandbox(session_id)returns the sandbox, including one a restore rebuilt: a replacement attempt re-seeding a restored session reuses it, and its setup does not run again.require_session_sandbox(session_id)answers 409 when the session has no sandbox, so a resent/verifyis refused instead of graded as reward 0.end_session_sandbox(session_id)stops the sandbox and forgets the session; its snapshots stay until a release drops the checkpoints that name them.shared_provider()is for sandboxes that are not session state, such as SWE-bench's grading sandbox.stopparks the exported sandboxes (sandbox_checkpoint.on_stop), andrelease_external_statedeletes the snapshots of checkpoints the controller no longer keeps.Per-session data. Some servers learn at seed what verify needs and cannot recompute once the agent has worked; the SWE family keeps
base_commitandpristine_untrackedin process memory, which a restore loses. Asetupmay return a small JSON object (SessionData). The base exports it next to the snapshot, restores it all or nothing with the sandbox, and drops it when the session ends;session_data(session_id)reads it. SWE-bench returns none (verify diffs the working tree in the sandbox), so its exported state keeps its shape.Checkpoint only what can be captured. With checkpointing on, the server decides its mode at startup through a new
SimpleResourcesServer.checkpoint_mode_in_effect()hook, whose default is the declaredcheckpoint_mode:lends_sandboxes()false) runsrestart_only. SWE-bench's golden-patch instance only grades the dataset's own patch, with 8 workers; training configs load it next to the agent-facing instance, so it must neither need astate_dirnor trip the worker guard.restart_onlyand one warning:swebench: sandbox provider 'apptainer' cannot snapshot; its rollouts restart after a crash instead of continuing. Before, every commit with a session in flight failed. Building the provider at startup also turns a bad provider config into a startup error.exported. Release and park do not reach the workers of a multi-worker server yet, so anexportedowner refuses to start withnum_workers > 1, and requirescheckpoint.state_dir.Leaving without a verdict.
/close_sessionwith an empty body ends the cookie's session, the conventionswebench_proalready serves. A checkpointed agent run that fails or is cancelled closes its session this way instead of stopping a sandbox the owner may still export (#4274). A typedResourcesCloseSessionRequestgets the base default.SWE-bench on the base. SWE-bench keeps its sandbox spec, the multilingual patch, the anti-cheat scrub (now inside
setup, so a failed seed no longer leaks a tracked sandbox), patch extraction, and grading.lends_sandboxes()returnsnot is_verifying_golden_patch.SandboxCheckpointConfigmoves tonemo_gym/sandbox/checkpoint.py.The second user. The e2e
sandbox_notes_server(#4221) runs on the base, so the process-level sandbox scenarios (restore, drift, lease expiry, release, a failed snapshot, the harness runs) exercise it. Its setup returns a seed token and its verify rewards nothing without it, so every crash scenario proves the session data survives a process-level restore.How it works
Where this PR sits in the overall flow
The highlighted part is what this PR adds.
flowchart LR C["Controller<br/>NeMo RL"] CO["Coordination<br/>prepare, commit, restore, resume,<br/>retire, release"] subgraph G["One participant per Gym server"] A["Agent<br/>runs the harness in the lent sandbox"] R["SandboxOwnerResourcesServer<br/>SWE-bench, notes server:<br/>seed, snapshot, fork, release,<br/>/sandbox_access, /close_session"] end P["Shared provider<br/>OpenSandbox: snapshots;<br/>others: restart_only"] S[("Sandbox per session<br/>+ session data")] I[("Snapshot index<br/>checkpoint.state_dir")] C --> CO --> G A -- "seed, /sandbox_access, verify, close" --> R R --> P --> S R --> I classDef this fill:#fde68a,stroke:#b45309,stroke-width:2px,color:#1f2937 class R thisWhich mode a server runs in
flowchart TD S["server starts"] --> CK{checkpointing on?} CK -- no --> OFF["unchanged: no provider, state_dir<br/>or worker checks at startup"] CK -- yes --> L{"lends_sandboxes()?"} L -- "no (golden-patch instance)" --> RO["restart_only"] L -- yes --> P{"provider can snapshot?"} P -- no --> W["restart_only + one warning"] P -- yes --> N{"num_workers > 1?"} N -- yes --> X["refuse to start"] N -- no --> E["exported<br/>(checkpoint.state_dir required)"]A session through a checkpoint, a crash, and verify
sequenceDiagram participant A as Agent participant R as SandboxOwnerResourcesServer participant P as Provider A->>R: /seed_session R->>P: start sandbox S1, run setup (patch, anti-cheat) Note over R: tracked only now, with setup's data R-->>A: sandbox_handle S1 Note over R: commit: snapshot S1, index it, export {sandbox, workdir, data} Note over R: crash, fresh process, restore R->>P: fork the snapshot into S2, stop S1 Note over R: S2 installed with the workdir and data, all sessions or none A->>R: /seed_session (replacement attempt) R-->>A: S2 (setup does not run again) A->>R: /sandbox_access R-->>A: S2 and its workdir A->>R: /verify Note over R: require S2 (409 without it), extract, end the session Note over R: release(kept) later deletes the dropped checkpoints' snapshotsWhere this sits in the stack
Stack #4578, on
ananthsub/partial-ckpt-fault-tests:release, the snapshot index, the OpenSandbox leaseIssue
Part of #3284 (sandboxed blackbox agents).
Validation
Run in the r3Run nemo-rl+Gym container on Slurm against this head, on
ananthsub/partial-ckpt-fault-tests8947bb2ca(job 1289959 suites, job 1289960 e2e):tests/unit_tests/test_sandbox_owner.py(new, 15) with a fake snapshot provider and a fake provider without snapshots:{}; a restore with one malformed state installs nothing and forks nothing;end_session_sandboxdrops the data;/verifywithout a sandbox answers 409;/close_sessionstops the sandbox, succeeds again when already closed, and the closed session is not exported; a typed body gets the base default, a malformed one a 422;restart_only: the seed reply carries the restart header, a commit with the session in flight succeeds and writes no record, nostate_diris needed, and the warning is logged once;exportedowner with 2 or 8 workers refuses to start, arestart_onlyone with 2 starts; an instance that lends no sandbox startsrestart_onlywith 8 workers and builds no provider, checkpointer orstate_dir; with checkpointing off nothing is checked at startup.resources_servers/swebench/tests39 passed in a venv with theswebenchharness, including a golden-patch instance that startsrestart_onlywith checkpointing on and 8 workers. The existing checkpoint tests changed only where they patch the provider resolution.tests/e2e/checkpoint(NEMO_GYM_CHECKPOINT_E2E=1): 61 passed, 12 skipped (real-model and scale cases), including the sandbox scenarios on the notes server, now built on the base, whose verify rewards nothing without the seed token its setup returned.tests/unit_tests/test_checkpoint_*.py783 passed; sandbox 227 passed; Simple Agent 73; the session-state and single-turn examples, rollout collection and ViBench 532.ruff checkandruff format --checkwith CI's ruff 0.9.9 clean on the changed files. Every commit carriesSigned-off-by.Rollout evidence
On the cell-5 OpenSandbox cell, with the OpenCode agent (#4274) and a nano-3.5 SWE SFT policy on 8 SWE-bench Verified rows, on this series' tip
dc39546d6(jobs 1289962, 1289967):resources: sandbox provider 'opensandbox' cannot snapshot; its rollouts restart after a crash instead of continuingonce at startup, a commit with every rollout in flight succeeded with no record, and all 8 verified.Compatibility
restart_onlyinstead of failing commits; an instance that lends no sandbox runsrestart_only; anexportedowner refusesnum_workers > 1and requirescheckpoint.state_dir.nemo_gym.sandbox.owner(SandboxOwnerResourcesServer,SandboxOwnerConfig,SessionData) andSimpleResourcesServer.checkpoint_mode_in_effect().SandboxCheckpointConfigmoved fromresources_servers/swebench/app.pytonemo_gym/sandbox/checkpoint.py.{sandbox, workdir}).🤖 Generated with Claude Code