Skip to content

fix(checkpoint): leave the calls a checkpoint abandoned out of the capture ledger - #4451

Draft
pthombre wants to merge 1 commit into
pthombre/partial-ckpt-sandbox-opencodefrom
pthombre/partial-ckpt-sandbox-capture
Draft

pthombre wants to merge 1 commit into
pthombre/partial-ckpt-sandbox-opencodefrom
pthombre/partial-ckpt-sandbox-capture

Conversation

@pthombre

@pthombre pthombre commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

What changed and why

A harness that gives up on a model call while a checkpoint holds it abandons that call. Examples are OpenCode stopped at a checkpoint (the fallback when a pause cannot be confirmed, #4274) and a run cancelled while its call is held.

With token capture on, the ledger had already recorded the call, often as a failure row for a request that ended without staging coordinates. Once the request had finished, the policy gate no longer counted it as undelivered, so the row went into the commit. The restored attempt's manifest then reported a failure for a call that no trajectory contains, which masks the sample.

What this PR adds:

  • The policy gate remembers abandoned calls: calls whose client left while admission was closed (PolicyGate.abandoned, carried in GateSnapshot.abandoned).
  • The commit leaves their rows out, as it does for an undelivered call.
  • The resume drops them from the live ledger (FileLineageStore.discard_calls).
  • Both policy servers: this works in the single-process and the multi-worker policy server (model_workers.py).

With #4274's pause-at-checkpoint, OpenCode keeps its held call across an in-job checkpoint and reads the reply on continue, so in-job checkpoints rarely abandon a call now. This PR still covers the stop fallback, cancelled runs, and any harness that does not pause.

How it works

sequenceDiagram
  participant H as Harness
  participant G as Policy gate
  participant L as Capture ledger
  participant C as Checkpoint
  H->>G: model call (admitted)
  G->>L: row for the call
  C->>G: close admission (the reply is held)
  H--xG: the client leaves (stopped or cancelled)
  G->>G: remember the call as abandoned
  C->>G: commit
  G-->>C: records without the abandoned call's row
  C->>G: resume
  G->>L: discard the abandoned call's row
Loading

Where this sits in the stack

Stack #4578, on ananthsub/partial-ckpt-fault-tests:

  1. feat(sandbox): sandbox and snapshot lifecycle for partial-rollout checkpoints #4220: sandbox checkpointer, release, snapshot index, sandbox lease
  2. feat(checkpoint): process-level evidence for resources-owned sandbox checkpoints, their release, and lease expiry #4221
  3. feat(checkpoint): ask a long-running agent harness to park when a checkpoint opens #4222
  4. feat(sandbox): sandbox owner base for resources servers, with SWE-bench on it #4576
  5. feat(checkpoint): harness driver for sandboxed agents that pauses them at checkpoints, with OpenCode on it #4274: the harness driver with pause-at-checkpoint, with OpenCode on it
  6. fix(checkpoint): leave the calls a checkpoint abandoned out of the capture ledger #4451 (this PR)
  7. fix(checkpoint): wake sandbox command polls while a harness launch is stopped #4553: wake sandbox command polls while a harness launch is stopped; checkpoint-resume docs
  8. feat(checkpoint): prepared verification, so a checkpoint never waits for SWE-bench grading #4778: prepared verification
  9. feat(sandbox): take a failed checkpoint snapshot again before failing the export #4779: retry a failed checkpoint snapshot
  10. fix(token-id-capture): match a tool call OpenCode rewrote as unavailable #4936: match a tool call OpenCode rewrote as unavailable

The change itself touches only the policy model participant and the capture ledger, independently of the sandbox work below it. It is stacked here because the OpenCode run in #4274 is what exposes it. The patch is unchanged from the previous head; only its base moved.

Issue

No tracking issue.

Validation

On this head (c526f2d06; its tree is identical to d3416046a, tested in the rl-gym.nightly container on Slurm, job 8085409):

  • Gym suites (SWE-bench, OpenCode, and the checkpoint, sandbox, OpenSandbox and token-capture unit tests): 2298 passed, 9 skipped, 0 failed.
  • ruff is clean, and the commit carries Signed-off-by.

The test for this change: tests/unit_tests/test_checkpoint_model.py::test_a_call_abandoned_while_held_is_left_out_of_the_commit_and_dropped_at_resume. A call held at prepare whose client leaves is excluded from the commit's records, and is gone from the live ledger after the resume.

Earlier, on the previous head (the series tip rebased on ananthsub/partial-ckpt-fault-tests 6f3184eaf, jobs 1246655 and 1246856): checkpoint 758 passed, provider 145, sandbox 211, every pilot passed, and e2e 68 passed.

Rollout evidence

Earlier capture-enabled cell-5 run (job 1186019; scenario B, rows 40–47, TOKEN_CAPTURE=1 behind a staging shim):

  • Prepare took 6.8 s, and commit took 25.7 s with 6 snapshots.
  • The committed capture rows equal the live ones, with 0 failure rows.
  • The restore took 12.7 s for 5 rollouts. For every restored rollout, the restored prefix matched, the uncommitted calls were absent, and the first new call continued the last committed one.

32-node runs with the whole stack (jobs 8093570 on the current stack, and earlier 8078235 and 8080199 → 8081456; details in #4274):

  • The lineage audits found 0 dangling parents, 0 branches and 0 token breaks.
  • No call admitted after a commit was kept by a restored rollout.

Compatibility

None. Only calls abandoned while admission was closed are affected, and they never belonged in a commit.

🤖 Generated with Claude Code

@copy-pr-bot

copy-pr-bot Bot commented Oct 11, 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.

@pthombre
pthombre added this pull request to stack #3962 October 11, 2026 04:45
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from 04804ff to df592e9 Compare October 12, 2026 21:53
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from df592e9 to 7e828a1 Compare October 12, 2026 21:57
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from 7e828a1 to bc000e6 Compare October 13, 2026 16:24
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch 2 times, most recently from 03e0349 to 2f563ae Compare October 13, 2026 20:27
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from 2f563ae to 9665a00 Compare October 13, 2026 20:45
@pthombre
pthombre removed this pull request from stack #3962 October 13, 2026 21:49
@pthombre
pthombre added this pull request to stack #4577 October 13, 2026 21:49
@pthombre
pthombre removed this pull request from stack #4577 October 13, 2026 21:52
@pthombre
pthombre added this pull request to stack #4578 October 13, 2026 21:53
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from 9665a00 to d3e1f94 Compare October 14, 2026 08:05
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from d3e1f94 to b7a7e19 Compare October 14, 2026 15:30
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from b7a7e19 to 65f68ba Compare October 14, 2026 17:24
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from b925d6c to c49ff45 Compare October 15, 2026 19:48
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from c49ff45 to 7a6340e Compare October 15, 2026 20:03
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from 7a6340e to f464f9d Compare October 15, 2026 20:30
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from f464f9d to 1c79fe9 Compare October 16, 2026 00:17
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from 1c79fe9 to a192974 Compare October 16, 2026 08:40
@ananthsub
ananthsub removed this pull request from stack #4578 October 16, 2026 19:01
@pthombre
pthombre added this pull request to stack #4696 October 16, 2026 19:45
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch 2 times, most recently from dc39546 to d341604 Compare October 20, 2026 07:51
@svcnvidia-nemo-ci svcnvidia-nemo-ci added area:model Model servers, inference providers, and model adapters bug Something isn't working labels Oct 20, 2026
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch 2 times, most recently from c526f2d to d36ba57 Compare October 20, 2026 22:18
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from d36ba57 to 501a150 Compare October 21, 2026 03:04
@pthombre
pthombre force-pushed the pthombre/partial-ckpt-sandbox-capture branch from 501a150 to 52c1a6e Compare October 25, 2026 02:47
…pture ledger

A harness interrupted at a checkpoint (OpenCode killed while its model call is held) gives up on the call. The
ledger had recorded it, often as a failure row for a request that ended without staging coordinates, and the
gate no longer counted it as undelivered once the request had finished, so the row went into the commit and
the restored attempt's manifest reported a failure for a call no trajectory contains, which masks the sample.

The policy gate now remembers calls whose client left while admission was closed (`GateSnapshot.abandoned`);
the commit leaves their rows out like an undelivered call's, and the resume drops them from the live ledger
(`FileLineageStore.discard_calls`), in the single-process and the multi-worker policy server alike.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Pranav Prashant Thombre <pthombre@nvidia.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:model Model servers, inference providers, and model adapters bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants