fix(contexts): mount writeable contexts from an exact durable snapshot, not a stale executor cache - #2328
Merged
Conversation
…t, not a stale executor cache A writeable (mutable) context was mounted from context_dir(name) on the executor's long-lived local disk, which is only hydrated from durable storage when empty. A writeback made on another executor/replica, or an operator edit made through the API container, was never re-pulled, so a run read a stale mutable pack (not visible to other workers / next run). Add a set_context_mount_snapshot_hook seam (mirrors the hydration/refresh hooks). writeable_mount_source(name) yields a fresh EXACT snapshot of the pack materialized from durable storage in hosted mode, and context_dir(name) unchanged in OSS/single-tenant mode. Both mount paths (e2b_driver _upload_contexts_to_sandbox and agent_capabilities stage_context_packs) use it for writeable local contexts; read-only contexts keep the cheap local cache. The snapshot is exact (a file deleted upstream is absent, so writeback cannot resurrect it) and fail-closed (a listing/download failure aborts the mount as retryable rather than mounting stale mutable data). The long-lived canonical cache is never mounted or mutated, so a concurrent run's writeback cannot be read torn. Regression test: apps/api/tests/test_writeable_context_mount_snapshot.py. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Problem
A worker writing to a shared, writeable context ("memory") during a run did not reliably see other workers' / prior runs' writebacks. Reported by a cloud user (Nima).
Root cause
The writeback -> durable-storage path is wired and works. The gap is on the mount side: a writeable (mutable) context is mounted from
context_dir(name)on the executor's long-lived local disk, which is only hydrated from durable storage when empty (hydrate_if_missing/_cloud_context_dirboth skip-if-nonempty). So once a container has a pack on disk, a writeback made on another executor/replica, or an operator edit made through the separate API container, is never re-pulled and the run mounts a stale mutable pack. Writeable contexts are exactly the ones whose source of truth is the durable store, not the cache.Design reviewed with Codex (adversarial): overwriting the live cache in place was rejected (it races with the worker process's synchronous writeback and the existing downloader is overlay-only, resurrecting deleted files). The accepted design is an immutable per-run snapshot.
Fix
Add a
set_context_mount_snapshot_hookseam (mirrors the existing hydration/refresh hooks).writeable_mount_source(name):context_dir(name)unchanged (local disk IS the durable store).Both mount paths use it for writeable local contexts:
e2b_driver._upload_contexts_to_sandboxandagent_capabilities.stage_context_packs. Read-only contexts keep the cheap local cache.Properties:
The cloud registers the hook (
downloadthe exact Storage contents into the temp dir) and bumps this submodule; that PR is separate.Out of scope (documented)
Full cross-process concurrent-writeback correctness (two runs writing the same pack simultaneously) still needs a per-
workspace_id/context_namelock or generation/CAS + delta writeback. Pre-existing last-writer-wins behavior is unchanged here.Tests
apps/api/tests/test_writeable_context_mount_snapshot.py(7 tests): seam with/without hook, exact snapshot + cleanup, fail-closed propagation, decline-fallback, and both mount paths staging the durable snapshot (not the stale cache). Fail-before/pass-after by construction (cache=v1, durable=v2 -> mounts v2).Existing context suite: 64 passed, no regressions.
🤖 Generated with Claude Code