Skip to content

fix(harness): keep persisted snapshot id when resume falls back to fresh create - #2775

Open
Buktal wants to merge 1 commit into
agentscope-ai:mainfrom
Buktal:fix/sandbox-resume-fallback-keeps-snapshot
Open

fix(harness): keep persisted snapshot id when resume falls back to fresh create#2775
Buktal wants to merge 1 commit into
agentscope-ai:mainfrom
Buktal:fix/sandbox-resume-fallback-keeps-snapshot

Conversation

@Buktal

@Buktal Buktal commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

AgentScope-Java Version

2.0.1 (fix developed against current main, bf7b7dae)

Description

Fixes #2771.

Background. With a harness-managed sandbox (filesystem(SandboxFilesystemSpec)) backed by the stock KubernetesSandboxClient, the workspace silently resets on every call and each snapshot archive is orphaned:

  1. create() sets claimOwned=true, so the per-call release (stop()shutdown()terminate()) deletes the claim/pod at the end of every call.
  2. On the next call, Priority 3 resume throws (getSandbox(claimName) fails — the claim is gone) and SandboxManager.acquire() falls through to the Priority 4 fresh create.
  3. The fresh create uses a new sessionId, so snapshotSpec.build(newSessionId) produces a new snapshot id: the previous archive is never referenced again, and start() runs the fresh-init branch — all files written in previous calls are gone, with only the P3 fallback warn as a trace.

The 4-branch workspace-start logic (Branch B/C restore) exists for exactly this situation but is unreachable on Kubernetes, because the resume never succeeds. Docker works because its resume() does not require a live container.

Change. In SandboxManager.acquire(), when a persisted state was loaded but the resume failed, the fresh-create fallback now carries the persisted snapshot id over to the new sandbox (rebuilding the snapshot from the current spec, so it carries a bound client regardless of deserialization). The next start() then restores the workspace from the previous archive (Branch C), and the next stop() overwrites that same archive instead of orphaning it.

The fix is client-agnostic: it applies to any SandboxClient whose resume can fail after its backing runtime is gone.

How to test. Two new unit tests in SandboxManagerIsolationTest:

  • priority3_resumeFails_freshCreateCarriesOverPersistedSnapshotId — resume throws → fresh create re-seeds state.snapshot via snapshotSpec.build(persistedId)
  • priority3_resumeFails_noPersistedSnapshot_keepsFreshSnapshot — no persisted snapshot → fresh snapshot untouched

Full harness module suite: mvn -pl agentscope-harness test — all passing.

Checklist

Please check the following items before code is ready to be reviewed.

  • Code has been formatted with mvn spotless:apply
  • All tests are passing (mvn test)
  • Javadoc comments are complete and follow project conventions
  • Related documentation has been updated (e.g. links, examples, etc.)
  • Code is ready for review

…esh create

When the Priority 3 resume fails (e.g. KubernetesSandboxClient.resume()
throws because its claim/pod was terminated on the previous release), the
Priority 4 fresh create built a brand-new snapshot id: the workspace
silently reset to the spec on every call and each previous archive was
orphaned. Carry the persisted snapshot id over to the fallback sandbox so
Sandbox#start() restores the workspace from the previous archive (start
Branch C) and Sandbox#stop() overwrites that same archive. The snapshot
is rebuilt from the current spec, so it carries a bound client regardless
of how the persisted state deserialized.

Fixes agentscope-ai#2771
@Buktal Buktal closed this Aug 19, 2026
@Buktal Buktal reopened this Aug 19, 2026
@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.00000% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...entscope/harness/agent/sandbox/SandboxManager.java 80.00% 0 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

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

Labels

None yet

Projects

None yet

1 participant