Parent RFC: #1286
Depends on:
Unblocks:
Summary
Define and implement the coordinator that produces one consistent, filtered, quiescent state/ + workspace/ snapshot for SessionBundleFileService.pack.
The coordinator owns the transition from live mutable Session roots to an immutable private staging snapshot. The filesystem codec continues to own only deterministic archive encoding, validation, and hydration.
Problem
SessionBundleFileService.pack accepts a PreparedSessionBundleSnapshot and assumes that:
- state and workspace represent one logical point in time;
- SQLite and other mutable stores are safe to copy;
- the roots do not change while packing;
- credentials, temporary execution state, logs, and excluded workspace content are absent.
Those guarantees do not exist when state/ and workspace/ are copied directly from a live Session. A state export and workspace copy taken at different times can produce a structurally valid but semantically inconsistent Bundle.
Responsibility boundary
The coordinator owns:
- acquiring a per-Session safe/quiescent boundary;
- coordinating the state export and workspace copy under that boundary;
- applying a versioned snapshot/filtering policy;
- producing the opaque state-identity descriptor through the state-owning layer;
- publishing a private immutable staging snapshot;
- retaining cleanup ownership until the caller releases the snapshot;
- deterministic failure cleanup and bounded stable errors.
It does not own:
- USTAR/Zstandard encoding or Bundle validation;
- Repository/blob persistence, revision allocation, or CAS;
- Activation leases, deduplication, reply publication, or sandbox lifecycle;
- Cloud Session fork orchestration or identity re-keying.
Proposed lifetime contract
V1 uses a short quiescence interval followed by a private staging copy. It does not keep the live Session blocked while compression and upload run.
Conceptually:
interface PreparedSessionBundleHandle {
snapshot: PreparedSessionBundleSnapshot;
/** Idempotently deletes the coordinator-owned private snapshot. */
release(): Promise<void>;
}
interface QuiescentSessionSnapshotCoordinator {
prepare(input: PrepareSessionSnapshotInput): Promise<PreparedSessionBundleHandle>;
}
Lifecycle:
- Serialize snapshot preparation for the Session and prevent new writers from entering the snapshot boundary.
- Wait for current state/workspace writes to settle, subject to caller cancellation/deadline.
- Export the single-Session state and copy the filtered workspace into a uniquely named, coordinator-owned private staging root.
- Keep state and workspace under the same quiescence interval until both copies and the state-identity descriptor are complete and all handles are closed.
- Release the live Session boundary before returning the handle.
pack reads only the private staging roots; later mutations of the live Session cannot affect the snapshot.
- The caller invokes
release() in finally; release is idempotent and removes only roots proven to be owned by this handle.
The coordinator must not return live Session paths as prepared snapshot paths.
Concurrent mutation and failure behavior
- Concurrent snapshot preparations for one Session are serialized.
- A writer that already owns the Session mutation boundary is allowed to finish before copying begins; preparation obeys the caller's deadline/cancellation.
- New writers cannot overlap the coordinated state/workspace copy.
- Unexpected source changes detected during preparation fail closed with a stable
source_changed-class error; no snapshot is returned.
- Any failure before a handle is returned removes partial staging state.
- Any failure after a handle is returned remains the caller's responsibility through
release().
- Temporary-root ownership must be explicit and persistent enough that cleanup cannot delete unrelated directories or follow symlinks.
- Orphan cleanup, if exposed, is scoped to an exact snapshot/owner record rather than a name-prefix sweep.
Filtering and secret-exclusion ownership
The coordinator is the enforcement point for a versioned snapshot policy. The codec and SessionRepository must not reinterpret this policy.
The V1 policy must deterministically exclude at least:
- host/global configuration and credential stores;
- control-plane-injected credentials and connection configuration;
- temporary Activation input and execution scratch space;
- logs, caches, and sandbox-local runtime state;
node_modules/ and .git/ from the portable workspace snapshot.
Project manifests and lockfiles remain included so project dependencies can be materialized in the target environment from a platform-keyed cache. Maka runtime dependencies belong in the versioned runtime image.
The policy must operate on normalized relative paths, fail closed on invalid or conflicting paths, and produce auditable exclusion diagnostics without exposing secret values.
Decision required before implementation: user-authored secrets
The contract still needs maintainer agreement on files deliberately present inside the user's workspace, such as .env, private keys, or credentials.json. Candidate policies are:
- detect and reject the complete snapshot with a bounded error (preferred over silently changing workspace semantics);
- deterministically exclude matched files and report the exclusions;
- allow them only through an explicit caller-owned policy/consent mechanism.
V1 must choose one explicit behavior before implementation. It must not rely on an undocumented best-effort scanner or silently default to including detected secrets.
Stable error model
The public error set should remain bounded, with structured details that do not expose unbounded paths or secret contents. Candidate codes:
type SessionSnapshotErrorCode =
| "snapshot_busy"
| "snapshot_cancelled"
| "source_changed"
| "unsafe_source"
| "policy_rejected"
| "quota_exceeded"
| "cleanup_failed"
| "io_failure";
Exact names remain subject to contract review.
Acceptance criteria
Consistency and lifetime
Cleanup and ownership
Filtering and security
Integration
Implementation split
This issue is one dependency-graph work item and should land independently from SessionRepository. A reviewable implementation may use two PRs if necessary:
- contract, quiescence/lifetime abstraction, policy boundary, and deterministic test fakes;
- filesystem/state integration, cleanup, race tests, and codec round-trip E2E.
Out of scope
- SessionRepository/KV/object-store implementation;
- revision retention, blob GC, or copy-on-write;
- OpenSandbox transfer;
- Activation execution and terminal-outcome persistence;
- Cloud Session fork orchestration;
makaSessionId or Workspace UUID re-keying;
- pending-approval or externally resumable action migration.
Parent RFC: #1286
Depends on:
Unblocks:
Summary
Define and implement the coordinator that produces one consistent, filtered, quiescent
state/ + workspace/snapshot forSessionBundleFileService.pack.The coordinator owns the transition from live mutable Session roots to an immutable private staging snapshot. The filesystem codec continues to own only deterministic archive encoding, validation, and hydration.
Problem
SessionBundleFileService.packaccepts aPreparedSessionBundleSnapshotand assumes that:Those guarantees do not exist when
state/andworkspace/are copied directly from a live Session. A state export and workspace copy taken at different times can produce a structurally valid but semantically inconsistent Bundle.Responsibility boundary
The coordinator owns:
It does not own:
Proposed lifetime contract
V1 uses a short quiescence interval followed by a private staging copy. It does not keep the live Session blocked while compression and upload run.
Conceptually:
Lifecycle:
packreads only the private staging roots; later mutations of the live Session cannot affect the snapshot.release()infinally; release is idempotent and removes only roots proven to be owned by this handle.The coordinator must not return live Session paths as prepared snapshot paths.
Concurrent mutation and failure behavior
source_changed-class error; no snapshot is returned.release().Filtering and secret-exclusion ownership
The coordinator is the enforcement point for a versioned snapshot policy. The codec and SessionRepository must not reinterpret this policy.
The V1 policy must deterministically exclude at least:
node_modules/and.git/from the portable workspace snapshot.Project manifests and lockfiles remain included so project dependencies can be materialized in the target environment from a platform-keyed cache. Maka runtime dependencies belong in the versioned runtime image.
The policy must operate on normalized relative paths, fail closed on invalid or conflicting paths, and produce auditable exclusion diagnostics without exposing secret values.
Decision required before implementation: user-authored secrets
The contract still needs maintainer agreement on files deliberately present inside the user's workspace, such as
.env, private keys, orcredentials.json. Candidate policies are:V1 must choose one explicit behavior before implementation. It must not rely on an undocumented best-effort scanner or silently default to including detected secrets.
Stable error model
The public error set should remain bounded, with structured details that do not expose unbounded paths or secret contents. Candidate codes:
Exact names remain subject to contract review.
Acceptance criteria
Consistency and lifetime
pack.packfinishes.preparereturns cannot change the prepared snapshot.Cleanup and ownership
release().Filtering and security
.git/, andnode_modules/are excluded.Integration
PreparedSessionBundleSnapshot.prepare -> pack -> inspect -> hydrate.Implementation split
This issue is one dependency-graph work item and should land independently from SessionRepository. A reviewable implementation may use two PRs if necessary:
Out of scope
makaSessionIdor Workspace UUID re-keying;