Seeded sandbox preservation
A sandbox's idle deadline must not erase an unpublished seeded checkout. The Worker is the protective boundary; attaching a future run, verified restore, publication and terminal-owner cleanup are separate work. This source change is not a deployed durability receipt.
- Code:
deploy/cloudflare-sandbox/worker.ts,src/execution/sandboxIdle.ts,src/execution/sandboxCheckpoint.ts,src/execution/sandboxOperationWindow.ts,src/execution/factory.ts,src/execution/cloudflareSandbox.ts,src/execution/seedPlan.ts - Tests:
src/execution/sandboxIdle.test.ts,src/execution/sandboxCheckpoint.test.ts,src/execution/sandboxOperationWindow.test.ts,src/execution/sandboxLifecycleReader.test.ts,src/execution/sandboxLifecycleStorage.test.ts,src/execution/sandboxLifecycle.test.ts,src/execution/factorySeedPreservation.test.ts,src/execution/cloudflareSandbox.test.ts,src/execution/seedPlan.test.ts
| Criterion | Proof |
|---|---|
| Before an idle-preservation SDK probe, a present versioned or malformed lifecycle record is retained. Pending, bound-but-unverified, closing and unknown records never enter the legacy unseeded destruction branch. A stopped container remains untouched; positively unseeded containers without an owner record and complete legacy seeded records keep their existing behavior. | [unit] src/execution/sandboxLifecycleReader.test.ts::sandbox preservation lifecycle reader::* |
| The common preservation metadata reader keeps unsupported versioned records explicitly unavailable. Seed preflight refuses them before warm-up or classification writes. Legacy checkpoint and birth writes reread the same storage key in a transaction, refuse new versioned or changed owner/origin/checkpoint data, and preserve normal legacy metadata. The reader and writer refusal survives an isolated SQLite Durable Object restart. | [unit] src/execution/sandboxLifecycleReader.test.ts::sandbox preservation metadata::*; src/execution/sandboxLifecycleStorage.test.ts::sandbox legacy storage writers::* |
| The local versioned lifecycle codec distinguishes complete legacy checkpoints, pending bindings and malformed or missing records without minting ownership or closing authority. Its fixed 16-slot operation window refuses overflow before effects, matches generation/actor/ordinal, retains unknown and reset-lost obligations, tracks detached work separately, handles duplicate/out-of-order callbacks and reads lost acknowledgments without replay. Checkpoint updates preserve the complete original owner, origin and lifecycle. Structural values and scoped operation completion never authorize physical retirement. | [unit] src/execution/sandboxOperationWindow.test.ts::sandbox lifecycle record::*; ::sandbox operation window::*; [gap] Operation reservation and settlement, canonical acknowledgment and physical retirement remain unwired; unsupported versioned storage is only held by the negative reader. |
| A legacy checkout backup returns only a typed stored/unknown observation. It cannot license seeded teardown: a detached writer may resume between pause samples and runtime custody remains outside the snapshot. The Worker retains after any observation; only the existing positively unseeded path may permit destruction. Complete physical exclusion, custody archive and original-store exact-version ACK are required before a final runtime can reclaim a seeded slot. | [unit] src/execution/sandboxCheckpoint.test.ts::checkpointIfSafe::never treats sampled pause around checkout upload as complete retirement evidence; src/execution/sandboxLifecycle.test.ts::sandbox Worker wiring (static)::declines a paused writer backup without an independent quiescence witness; [gap] The current default runtime has no complete all-writer capture/ACK capability; seeded reclamation remains held. |
A trusted owner claim accepts the same branch names as /seed, including +, while rejecting Git-reserved ref syntax. | [unit] src/execution/sandboxCheckpoint.test.ts::preservationReceipt::accepts a Git-valid seeded ref with a plus sign in an owner claim; src/execution/factorySeedPreservation.test.ts::initial sandbox seed owner provenance::forms the claim only from resolved run context and the exact checkout backup, never the model or dependency archive |
| Before idle or stuck teardown, a seeded writer's checkout is retained when quiescence, ownership, the incarnation or a complete backup cannot be proved. An in-flight stop and SDK expiry share this fence; a missing fence, same-tick request or failed backup never licenses clean or forced destruction. | [unit] src/execution/sandboxIdle.test.ts::IdleGuard preservation::retains if the preservation fence is missing or throws; ::retains an idle seeded writer when preservation is uncertain; ::retains a stuck in-flight writer when preservation is uncertain; ::retains on a same-tick request even when the idle clock does not advance; ::does not admit a new writer while teardown of an unseeded container is in progress; ::retains on failed backup and a concurrent request during preservation; src/execution/sandboxLifecycle.test.ts::sandbox Worker wiring (static)::fences both idle and SDK expiry teardown before SDK destroy or platform kill |
| A checkpoint, if independently safe quiescence is established, includes the checkout and its .git, excludes nothing by ignore rule, is tied to one owner and container incarnation, and has an SDK TTL beyond the maximum Ship idle window with grace. A failed upload, changed owner or incomplete verification retains the container; deletion requires verified terminal ownership (not implemented here). An attempted seed is durably marked before restore, even without an owner claim or after its marker is removed; an older unknown container also retains. | [unit] src/execution/sandboxCheckpoint.test.ts::checkpointIfSafe::backs up the complete checkout for longer than the Ship idle window; ::never snapshots a paused writer without an independent quiescence witness; ::retains when backup fails or the owner or incarnation changes; ::retains when ownership changes while an upload is in flight; src/execution/sandboxLifecycle.test.ts::sandbox Worker wiring (static)::a legacy or failed seed stays protected even when its container marker disappears; ::checks an earlier bound incarnation before seed can overwrite its checkout; ::declines a paused writer backup without an independent quiescence witness; [gap] Bucket lifecycle retention is not configured here; no live paused-writer backup is made or proven by this source-only unit. |
A bound owner's repeat /seed validates the original seed identity and incarnation, not the checkout's mutable HEAD: cached retries after a commit or with uncommitted work keep the checkout unchanged. If a writer removes or replaces the marker after the ownership pre-check, the second read refuses before any destructive fresh-seed sweep of the checkout or .git. Only a fresh seed must check its resulting HEAD against the claim. | [unit] src/execution/sandboxCheckpoint.test.ts::seedClaimHeadMatches::*; ::bound seed marker decisions::*; src/execution/seedPlan.test.ts::the seeded sandbox wiring (static)::a bound seed refuses a changed or missing second marker before restore, without a destructive sweep; ::a prior owner only accepts a cached answer and permits the checkout HEAD to advance; ::POST /seed parses the handle by field, then runs the seed inside the idle ledger and behind the start gate, streamed; src/execution/sandboxLifecycle.test.ts::sandbox Worker wiring (static)::a bound owner retries the original seed without requiring the checkout HEAD to stay at its seed commit |
An initial claimed /seed takes the run, requester, thread, repository, ref and resolved head only from trusted executor context and binds the exact checkout backup; the Worker returns its birth container and the bot records it in the seeded selection and durable workspace binding. Missing or mismatched claimed receipts refuse without a cold fallback; older unclaimed callers remain compatible. The Worker binds a credential-free HTTPS Git Door origin to that same owner at birth, refuses changed/missing origins or legacy unknown-origin records on exact-owner cached retries before touching origin or checkout, and never stores the bearer. | [unit] src/execution/factorySeedPreservation.test.ts::initial sandbox seed owner provenance::forms the claim only from resolved run context and the exact checkout backup, never the model or dependency archive; ::refuses conflicting or malformed context rather than minting an owner with wrong fields; ::posts the trusted claim and records the Worker container on the seeded selection and durable binding; ::refuses a claimed seed with missing or malformed container before recording a binding or falling cold; ::keeps an unclaimed legacy seed working without a preservation receipt; src/execution/cloudflareSandbox.test.ts::CloudflareSandboxExecutor seed::posts a typed owner claim in the body and accepts only a matching claimed seed receipt; ::fails closed on missing, malformed or mismatched claimed receipts but keeps unclaimed responses compatible; src/execution/sandboxCheckpoint.test.ts::trusted seed door origin::*; src/execution/seedPlan.test.ts::the seeded sandbox wiring (static)::binds the trusted seed door origin to the birth record and refuses changed or legacy origins before cached mutation |
| A passive read-only receipt requires the exact run, requester, thread, repository, ref, head, seed and container incarnation. It returns bounded present/lost/unknown facts only from durable metadata and R2 existence; a stopped container is never awakened for inspection or replaced. | [unit] src/execution/sandboxCheckpoint.test.ts::preservationReceipt::refuses every wrong owner or incarnation without disclosing a checkpoint; ::distinguishes present lost and unknown without reading checkout contents; ::a stopped-container receipt reads only durable facts and never wakes or starts replacement work; ::rejects malformed identities and arbitrary file or command fields; src/execution/sandboxLifecycle.test.ts::sandbox Worker wiring (static)::the stopped-container receipt bypasses getSandbox StartGate and exec |
| An exact-slot evidence read requires the named DO id and the complete immutable owner claim before disclosing its birth container or checkpoint state. It reads only durable metadata and R2, never starts or executes in the container. A matched running seeded slot remains retained even with a complete checkpoint: the current checkout bytes, exclusive ownership and detached-writer quiescence are unproven, so this receipt never permits retirement. | [unit] src/execution/sandboxCheckpoint.test.ts::passive slot evidence::reports a matched running owner and complete checkpoint as retained, never as a stop permit; ::discloses no owner or checkpoint when the DO, claim, or running state is uncertain; ::keeps a matching owner retained when the R2 checkpoint is missing; src/execution/sandboxLifecycle.test.ts::sandbox Worker wiring (static)::the exact-slot receipt bypasses getSandbox and native exec |
A checkpoint is only eligible when the Worker can establish quiescence without trusting a model assertion; the SDK's tracked-process list does not see detached writers, so this Worker currently retains seeded containers rather than making a paused-writer backup. A never-classified older container also stays retained; only a durable pre-start unseeded classification permits normal teardown. A model-root writer can remove the filesystem marker without clearing that durable fence. The bot sends a claim only when its trusted run context includes the resolved head and complete identity; callers without those facts remain unclaimed and their receipt is unknown, never falsely present. Existing records without a birth origin cannot be silently upgraded by retry. The receipt does not wake a container, authorize recovery, delete a backup, or claim live durability. Operators must verify bucket lifecycle retention and a natural paused-run receipt in separately authorized work; no source-only test substitutes for those observations.