Dash session ownership and export

Dash session ownership and export

SessionOwnershipService is the explicit boundary between preview-only Pi JSONL inventory and a managed Pi Daemon writer. Reading a transcript never acquires ownership. Direct co-opt, fork/import, export, append-back, and release are separate durable ticket operations.

The public modules are:

Storage authority

Pi Daemon may use two session storage policies:

The cwd-encoded project directory name (--<encoded cwd>--) is stock Pi behavior. Pi 0.82.1 implements it as getDefaultSessionDir() inside its internal core/session-manager module, which the package root does not re-export and the package exports map does not expose; the upstream helper also creates the directory with ambient permissions. Pi Daemon therefore owns one side-effect-free reproduction, piDefaultSessionDirectoryName() / piDefaultSessionDirectory() in pi-sdk-contract, and still creates every directory owner-private itself. test/pi-sdk-compatibility.test.mjs pins that reproduction against the real pinned SDK through its public API and fails when the encoding drifts or when a release starts exporting the helper, which is the signal to consume the upstream export (and the reason to prefer an upstream re-export of a path-only helper).

Workload cwd remains independently constrained to configured allowed roots. Inventory sources must be owner-owned regular non-symlink files under explicit private source roots and may not overlap daemon state.

Durable tickets and crash semantics

Every operation is scoped by kind, target, and idempotency key. Reusing a key with the same semantic request joins the retained ticket; different content conflicts. The owner-private STATE_DIR/web/ownership-v1.json contains bounded:

A restart leaves queued work replayable only when the caller repeats the same idempotent request. Running work becomes indeterminate and is never submitted again automatically.

Activation modes

A caller-supplied runtime-spec factory provides trusted model/tool/resource policy. The ownership service overwrites only cwd, target, storage directory, name, and the honest unisolated mode needed to make the activation identity exact; it never invents provider credentials or ambient tools.

Cooperative write guard

Stock Pi does not honor a shared cooperative lock. Direct mode therefore cannot claim a perfect cross-process mutex. Dash combines:

beforeManagedWrite() fails closed and marks external_write_conflict if a direct source changed. afterManagedWrite() accepts only a history preserving the recorded entry-ID prefix. checkForExternalConflicts() provides a bounded periodic guard. A conflict closes the runtime best-effort, preserves both files, and changes inventory ownership state rather than silently continuing.

Export

as-new writes a new current-version Pi session with a fresh UUID and parentSession metadata under the normal cwd-encoded Pi session directory. It uses an owner-private atomic publication and updates inventory immediately.

append-to-origin is available only for imported sessions. It requires:

  1. the origin's exact recorded fingerprint/stat identity is unchanged;
  2. no known external writer;
  3. the managed entries preserve the origin entries exactly as a prefix;
  4. the delta is one linear parent-ID continuation; and
  5. a second source revalidation immediately before atomic publication.

Any divergence returns external_write_conflict or managed_history_diverged; it never overwrites the origin. releaseAfterExport closes the managed runtime, marks ownership released, and refreshes inventory.

Integration

MultiplexerSessionOwnershipRuntime maps a trusted SessionSpec through the same parseSessionConfiguration(), catalog, generation, runtime, and close paths as the existing REST API. Embedded and remote DashboardBackend implementations call the neutral ownership service rather than reaching into inventory records or Pi Adapter internals.

The server/controller layer remains responsible for invoking the write guard at command boundaries and for supplying authoritative active-controller state.