Skip to content

fix(terminal-bench-science): raise sandbox disk limits and drop the S3 mount - #5334

Merged
gwarmstrong merged 2 commits into
NVIDIA-NeMo:mainfrom
gwarmstrong:georgea/tbsci-disk-s3-upstream
Oct 30, 2026
Merged

gwarmstrong merged 2 commits into
NVIDIA-NeMo:mainfrom
gwarmstrong:georgea/tbsci-disk-s3-upstream

Conversation

@gwarmstrong

@gwarmstrong gwarmstrong commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

What changed

  • resources_servers/terminal_bench_4: a new environment option, sandbox_min_disk_gib (unset by default, which changes nothing). When it is set, a role that declares storage_mb gets an ephemeral-storage limit of at least that many GiB. Under the provider option resource_requests: limits, the request becomes the declared resources, so the node still reserves only the declared storage_mb and the higher limit is headroom. Roles that declare no storage_mb keep having no limit.
  • benchmarks/terminal_bench_science: sets sandbox_min_disk_gib: 100 (override with ++tbsci_min_disk_gib=) and adds the sandbox label nemo.nvidia.com/s3-hostpath: 'false' beside the existing oom-kill label. Both changes are new rows in the README's table of deviations from the packages.

Why

Disk. Harbor's Docker backend, which the TB-Science leaderboard ran on, applies a task's CPUs and memory but not its storage_mb. OpenSandbox enforces the ephemeral-storage limit Gym sends by evicting the whole sandbox, with no "no space left" error first. In a probe, a sandbox with a 1 GiB limit wrote 2 GiB without a write error and was evicted about 10 s after it passed 1 GiB. Its status then read Pending for 15 minutes, so the runner learns of it only from a failed command. In seven full TB-Science runs on OpenSandbox, 26 tries were lost this way, on 11 tasks declaring 2 to 12 GiB (microarch-modeling 6 times in 5 runs). The cell accepts a 100 GiB limit; a sandbox with no limit kept 7 GiB.

S3 mount. By default the cell mounts a shared read-only S3 bucket at /mnt/s3-data in every sandbox. Its data is unrelated to the benchmark and Docker sandboxes have no such mount, but agents searched it for answers and whole-filesystem scans (find /) stalled in it. The cell's per-sandbox label nemo.nvidia.com/s3-hostpath: 'false' leaves it out, and /mnt is then empty. A deployment that does not know the label ignores it, as with oom-kill.

Issue

None. Found while running TB-Science on OpenSandbox; the evidence is below.

Validation

  • resources_servers/terminal_bench_4/tests: 264 passed, 1 skipped. New: test_min_disk_raises_the_limit_but_not_the_request covers the raised limit, the request staying at the declared resources under resource_requests: limits, explicit request mappings and no requests left unchanged, the provider config not mutated, roles without storage_mb staying unlimited, and larger declarations kept. The TB-Science profile test now checks the label on every role.
  • pre-commit run --all-files: passed, no changes.
  • Live probe of the cell (no model): the 1 GiB eviction above, a 100 GiB limit accepted, 7 GiB kept with no limit, and an empty /mnt with the label.
  • No-model oracle on this head (4e7992d): genomic-model-ranking, protein-active-learning and small-area-equivalence passed 3/3. All 11 sandboxes (agents, verifiers, Compose sidecars, log helpers) carried the label and saw an empty /mnt.

Rollout evidence

Codex 0.154.0 with self-hosted DeepSeek V4.1 Flash on OpenSandbox, on these two commits applied to an earlier main. 13 tasks x 3 trials at the 8-hour budget, chosen because earlier runs repeatedly lost them to evictions (7 tasks) or searched /mnt/s3-data in them (6 tasks). All 39 trials were graded.

  • Evictions: none, and no lost pod. Two earlier runs of the same setup without this change (70 tasks x 6 trials each) had 9 and 8 evictions on these 13 tasks: qsm-reconstruction 6 and 4, virtual-baseline-localization 2 and 2, supraglacial-lake-classification 1 and 2.
  • Trials past their declared disk kept running. Every 20 minutes I summed, in each running agent sandbox, the files created or modified since it started; that approximates the writable layer the limit counts, and misses peaks between samples. Three trials wrote past their task's storage_mb, so the previous limit would have evicted them, and all three were graded:
Task Declared Peak written Agent time Outcome
qsm-reconstruction 10 GiB 21.3 GB 7.0 h completed, graded
virtual-baseline-localization 4 GiB 8.2 GB 7.9 h completed, graded
virtual-baseline-localization 4 GiB 4.6 GB 8.0 h agent time limit, graded
  • S3: no trial reached /mnt/s3-data and none received an S3 path in a tool output (0 of 39). On the same 13 tasks, an earlier run with the same model had 7 of 78 trials name the path and 21 receive S3 file contents or paths.
  • find / returned in at most 5.4 s over 292 calls. Before, at least 10% of 478 calls ran past Codex's 30 s wait.
  • Unrelated to this change: 20 trials were cut off at 3 hours by an outage of our model gateway and were rerun to the full budget (the figures above use the reruns); one qsm-reconstruction sandbox stopped answering status reads at 3 h 20 min with no eviction reported (SandboxUnresponsiveError), and its retry is the 21.3 GB trial; one trial ended on a gateway 502.

Compatibility and benchmark impact

  • sandbox_min_disk_gib is unset by default, so other TB4 profiles are unchanged.
  • TB-Science on OpenSandbox: trials that used to be evicted now run to grading, and agents can no longer read the S3 bucket. Scores move toward the Docker setting the leaderboard used, so scores from earlier OpenSandbox runs are not strictly comparable.
  • Under resource_requests: limits only storage_mb is reserved, so the higher limit does not change packing. A sandbox that writes past its declared size uses node disk beyond its reservation.

sandbox_min_disk_gib raises a role's ephemeral-storage limit to at least that many GiB while the
declared storage_mb stays its request. Harbor's Docker environment enforces no storage limit, but
OpenSandbox evicts the whole sandbox once it writes past its limit, with no ENOSPC first. With
resource_requests: limits the request becomes the declared resources, so the node reserves only the
declared disk. Roles without storage_mb stay unlimited.

Signed-off-by: gwarmstrong <gwarmstrong@users.noreply.github.com>
Every sandbox gets nemo.nvidia.com/s3-hostpath: 'false', so the cell leaves out its shared read-only
S3 bucket at /mnt/s3-data (data unrelated to the benchmark; agents searched it for answers, and
whole-filesystem scans stalled in it). Disk limits rise to 100 GiB (++tbsci_min_disk_gib) while the
declared storage_mb is reserved: 26 tries in seven full runs were evicted for writing past 2-12 GiB,
which Docker allows.

Signed-off-by: gwarmstrong <gwarmstrong@users.noreply.github.com>
@copy-pr-bot

copy-pr-bot Bot commented Oct 29, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@svcnvidia-nemo-ci svcnvidia-nemo-ci added area:environment Individual environments, benchmarks, verifiers, and environment-specific resources servers bug Something isn't working needs-review PR is ready for code review and waiting on a reviewer labels Oct 29, 2026
@cmunley1

Copy link
Copy Markdown
Contributor

/ok to test 4e7992d

@gwarmstrong

Copy link
Copy Markdown
Contributor Author

The two pending items are done, and the description is updated.

  • No-model oracle on 4e7992d: 3/3 passed, all 11 sandboxes labelled with an empty /mnt.
  • The 39-trial run finished with every trial graded. There were no evictions, while the same setup without this change had 8 to 9 evictions per run on these tasks. Three trials wrote past their declared storage_mb and were still graded: qsm-reconstruction wrote 21.3 GB against 10 GiB, and two virtual-baseline-localization trials wrote 8.2 GB and 4.6 GB against 4 GiB. No trial reached /mnt/s3-data.

@svcnvidia-nemo-ci svcnvidia-nemo-ci left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SHIP WITH CARE

One RISK: enabling disk headroom freezes CPU/memory requests before Compose overrides, unintentionally changing main-service reservations.

Reviewed all five changed files and their directly affected provider, Compose, and log-helper paths. No other qualifying findings. Static review only; tests and reported rollouts were not executed or independently reproduced.

Review generated by codex. This was a full review. Request a full review with /review reset=true.

if resources.disk_gib is not None and resources.disk_gib < (config.sandbox_min_disk_gib or 0):
if options.get("resource_requests") == "limits":
# Reserve only the declared disk on the node; the higher limit is headroom.
options["resource_requests"] = {k: v for k, v in asdict(resources).items() if v is not None}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RISK — Preserve final Compose resource requests when adding disk headroom

Failure: With task resources cpus=2, memory_mb=4096, storage_mb=15000, floor 100, and resource_requests: limits, this branch freezes requests at {cpu: 2, memory_mib: 4096, disk_gib: 15}. A supported Compose main overlay of cpus: 4, mem_limit: 8g subsequently produces limits (4, 8192, 100) through the adapter's resource merge, without updating those requests. OpenSandbox's explicit-map branch only clamps requests downward, so it sends CPU/memory requests of 2/4096, not 4/8192. Before this change, limits remained deferred until after the Compose overlay. Affected main services are therefore under-reserved for CPU/memory merely because disk headroom was enabled.

Correction: Could the automatically derived requests be finalized after the main service's resource overlay? Coordinate Environment.start's service specification with AsyncSandboxCompose._prepare, using the normalized Compose resource contract. Reserve the effective CPU/memory/GPU values, but retain the original declared disk reservation. The invariant is that this option changes only disk limit versus request—not other resource_requests: limits semantics. The exact drop-in implementation across these layers remains uncertain; a blanket replacement of every request map would break explicitly configured requests.

Preservation and acceptance — proposed checks, not run:

  • Add an Environment-to-Compose regression for the setup above: final limits must be (4, 8192, 100) and requests (4, 8192, 15). Repeat with equivalent deploy.resources.limits values.
  • With a lower main override (1, 2048), requests must remain (1, 2048, 15); preserve the existing downward-clamping behavior.
  • An explicit request map such as {cpu: 1} must remain explicit and unchanged; omitted requests must remain omitted. Sidecars must continue deriving requests from their own effective resources, not the main role's map.
  • Retain the non-Compose disk-test assertions: raised limit 100 with disk request 15, immutable config options, no-storage verifier disk None, declaration 200 unchanged, and unset floor retaining disk 15. Also check a declaration equal to the floor remains unchanged.

@gwarmstrong
gwarmstrong added this pull request to the merge queue Oct 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA-NeMo/Gym/actions/runs/41097568760

Merged via the queue into NVIDIA-NeMo:main with commit 1043fd4 Oct 30, 2026
57 of 60 checks passed
@gwarmstrong
gwarmstrong deleted the georgea/tbsci-disk-s3-upstream branch October 30, 2026 18:02

This branch was previously deployed

1 inactive deployment
public — 4e7992dc Deployed Oct 30, 2026 by copy-pr-bot[bot] via release / finalize / notify #8568
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:environment Individual environments, benchmarks, verifiers, and environment-specific resources servers bug Something isn't working needs-review PR is ready for code review and waiting on a reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants