Browse architecture
Chapter 04

Private work becomes shared history exactly once.

A workspace session coordinates commands around one stable filesystem view. Finalization captures its private changes, resolves each path against head, and publishes one immutable layer or rejects everything.

Session contract

The orchestration boundary between private execution and shared state.

LayerStack owns durable history, namespace processes own execution boundaries, and OverlayFS owns the writable view. A workspace session holds their handles together and decides when lifecycle edges may cross.

Lease
Pins the immutable LayerStack view used as the session’s publication base.
Holder + namespace FDs
Keep the user, mount, PID, and optional network boundaries alive.
Overlay handle
Names the upperdir, workdir, and merged workspace owned by this session.
Admission gate
Serializes lifecycle edges without serializing admitted command runtime.
Command ledger
Tracks which namespace executions still belong to the session.
Finalize policy
Either retain the explicit session or publish-then-destroy an implicit one.
Create + rollback

Build forward, compensate backward.

Session creation crosses storage, process, network, mount, persistence, and registry boundaries. A failure never leaves the later resources alive while silently dropping an earlier owner.

  1. 01

    Acquire lease

    Pin the active manifest before any runtime state exists.

    on failure

    release lease

  2. 02

    Create scratch

    Allocate upperdir, workdir, run directory, and session identity.

    on failure

    remove run tree

  3. 03

    Spawn holder

    Create namespaces, capture FDs, and prepare optional isolated networking.

    on failure

    kill holder + free network

  4. 04

    Mount overlay

    Project the leased lower chain with the private upperdir.

    on failure

    namespace teardown

  5. 05

    Persist + register

    Write manager state, prepare the cgroup leaf, then insert the live session.

    on failure

    destroy or surface rollback failure

Admission gate + command ledger

Serialize decisions, not command runtime.

One mutex per session protects admission, completion, finalization, file operations, remounts, and guarded destroy. The mutex is released after a command is attached, so admitted commands still execute concurrently.

One command lifecycle

  1. 01

    Lock gate

    Resolve the live session and prevent a concurrent finalize, remount, file operation, or destroy.

  2. 02

    Insert ledger entry

    Attach the namespace execution ID before the runner can complete.

  3. 03

    Launch + attach

    Reserve execution capacity, start the runner, and connect its terminal outcome.

  4. 04

    Release gate

    The command runs concurrently after its lifecycle edge is committed.

  5. 05

    Complete

    Remove the ledger entry; an empty ledger may transition the session into finalization.

01

Active

Commands may be admitted; explicit sessions remain after the ledger drains.

02

Finalizing

No new work enters while capture, publish, and implicit teardown run under the gate.

03

FinalizeFailed

The session remains destroyable but cannot quietly return to normal admission.

Capture + publish pipeline

The upperdir closes the loop back into LayerStack.

Capture reads the actual OverlayFS upperdir. Planning uses only the immutable session base; conflict resolution moves under the writer lock and compares against the current active head.

  1. 01

    Capture

    Walk the upperdir and derive writes, symlinks, whiteouts, and opaque directories from kernel OverlayFS metadata.

  2. 02

    Plan

    Route paths and record expected content fingerprints against the session’s immutable leased base.

  3. 03

    Lock + resolve

    Acquire the LayerStack writer lock and compare actual fingerprints against the current active head.

  4. 04

    Merge or reject

    Accept equal paths, three-way merge eligible text, or reject the complete publication on conflict.

  5. 05

    Commit + attribute

    Promote one staged immutable layer, prepend the manifest, then append ownership evidence.

Kernel metadata, not filename folklore

Capture recognizes OverlayFS whiteouts and opaque directories from device or xattr metadata. A user-created filename beginning with .wh. is not silently reinterpreted as a deletion marker.

Optimistic concurrency control

Stale manifests are allowed. Conflicting paths are not.

Each changed source path carries an expected fingerprint from the leased base. Under the writer lock, LayerStack resolves the actual fingerprint from current head. This per-path comparison—not manifest freshness—is the real concurrency control.

Three inputs
basesession’s leased bytes
activecurrent head bytes
commandcaptured upperdir bytes

Eligible text is merged on line regions. The runtime emits clean bytes and structural origin ranges—never conflict markers.

Unchanged at head

expected = actual

accept command change

Disjoint text edits

merge(base, head, command)

publish merged bytes

Overlapping edits

different replacement regions

reject source_conflict

Non-text or oversized

merge ineligible

reject, no conflict markers

Ignore rules route attribution; they do not simply erase changes. Source-routed paths receive fingerprint validation and line origin, while ignored paths use wholesale attribution from the session base policy.

Atomic publication

Durable payload first. Manifest visibility last.

A resolved changeset is written into a nonce staging directory. Files and directories are synced before rename; the manifest is rechecked immediately before the new immutable layer becomes active.

  1. 01

    Write staging

    Materialize every resolved change under a unique temporary layer directory.

  2. 02

    Sync + rename

    fsync payload and tree, then atomically rename staging to its final L* path.

  3. 03

    Recheck head

    If the manifest changed after resolve, remove the promoted layer and report conflict.

  4. 04

    Prepend manifest

    Write the next version with L* first; only then can new leases observe it.

Empty or byte-identical output is a no-op. A rejection creates no partial layer and is surfaced on the command that triggered finalization.

Cost + attribution

Coordination scales with changed state, not the base checkout.

The shared base remains pinned and immutable. Session setup scales with lower-chain metadata; finalization scales with captured paths and affected bytes.

OperationDominant boundReason
Session createΘ(L)Build and pin an L-layer lower chain; no Θ(B) base copy.
CaptureO(C log C + bytes visited)Walk and deterministically order C upperdir changes.
ResolveO(C·L·P + H)Find C paths through L layers and hash or merge H affected bytes.
CommitO(changed bytes + manifest)Write one staging tree, sync, rename, and prepend metadata.

Attribution follows the resolved result

The merge records whether final line ranges came from active history or the command. After commit, those origins are mapped to runtime owners and appended outside the compactable layer store.

Related LayerStack model

File-operation blame