C1 is the production workspace effect boundary for Peritus. It turns already-authorized and durably observed action plans into explicit Git and filesystem operations while preserving exact workspace identity, mutation fencing, content history, and restart evidence.
The slice consists of three runtime-layer libraries:
| Crate | Responsibility |
|---|---|
peritus-git |
Structured Git repository, object, worktree, status, candidate, snapshot, restore, and reconciliation operations |
peritus-patch |
Checked relative paths, typed patch sets, deterministic plans, transactional application, rollback, and interrupted-transaction recovery |
peritus-workspace |
Read-only/writable state, exact authority gateway, resource/lease binding, candidate and rollback workflow, artifact manifests, and restart classification |
All three crates are verification class H. Deterministic validation and classification live in Verus Rust; Git subprocesses and filesystem operations are narrow effect shells. None of the crates can mark a run accepted, mint a B0/B1/C0 receipt, or merge into a user branch.
GitRepository opens an existing repository through fixed-shape Git commands. It resolves the
repository's canonical worktree/common-directory identity and reported object format, then parses
every commit and tree identifier into an ObjectId carrying an explicit SHA-1 or SHA-256 format.
Callers cannot submit raw Git argv.
Read commands disable optional locks. Repository-selection environment variables are cleared so a model-controlled environment cannot redirect an operation to another repository. User-controlled path and object values are passed as separate argv entries; shell parsing is never involved.
A Baseline contains the exact immutable commit and tree selected when a workspace is provisioned.
Branch names are resolution input only. Later operations retain the resolved object identity and do
not follow a moving branch ref.
CreateWorktree combines a checked WorktreeName, destination, immutable baseline, and
WorktreeAccess. Writable and read-only worktrees are detached from user branches. Existing
registrations or destinations are conflicts rather than implicit reuse.
Each registration has a bounded, versioned manifest. Normal restart recovery decodes that
manifest, revalidates its repository and worktree binding, and reconstructs a fresh handle instead
of trusting process-local state. If Git created the linked worktree but the caller stopped before
persisting a manifest, recover_existing_worktree instead takes the original checked
CreateWorktree request and adopts only the exact registered destination at the requested
detached baseline.
Removal is explicit and targets the exact registered worktree. A dirty worktree is not silently discarded. C1 never rewrites a user branch and never treats the primary checkout as disposable.
Status uses NUL-delimited porcelain-v2 records. StatusObservation preserves tracked, untracked,
ignored, renamed, conflicted, and submodule classifications plus exact HEAD/tree facts and a
canonical digest. Status always inspects submodules and requires detached workspace topology;
repository configuration cannot hide those facts. Malformed or oversized Git output is a protocol
error.
Candidate creation operates only in the isolated writable worktree. It stages the allowed
filesystem result and writes a content-addressed Git tree without advancing a user ref. Any
configured filter.*.clean, filter.*.smudge, or filter.*.process key is rejected before a
filter-capable Git effect; built-in attribute behavior without an external driver remains allowed.
Candidate and snapshot manifests are bounded, versioned, digestible, and decodable after restart;
a retained snapshot manifest can be revalidated into a fresh CandidateSnapshot handle.
CandidateSnapshot reports the exact workspace and snapshot IDs, commit, tree, retaining ref, and
snapshot-manifest digest. C1-owned refs live below refs/peritus/workspaces/.
WorkspacePath is the only file-target type accepted by a PatchSet. It represents one bounded
UTF-8 path relative to a workspace root. Construction rejects absolute paths, traversal, empty
components, alternate separators, control bytes, protected metadata, reserved device names, and
other forms that cannot be interpreted consistently.
Before mutation, resolution checks that the canonical workspace root still matches its opened identity, rejects symlink components/final targets, and revalidates the containing directory. The portable C1 checks are supplemented later by C3's native sandbox enforcement.
A patch binds:
- a stable
PatchIdentity; - exact
WorkspaceId,Generation, andRevisionNumberexpectations; - a bounded canonical list of unique target paths;
- create, replace, or delete intent;
- an absent or exact present
Preimage; - final SHA-256 digest and byte length;
- regular or executable
FileMode; and - preserve, LF, or CRLF
LineEndingPolicy.
PatchSet::new validates path ordering, conflicts, content and preimage bounds, and the worst-case
recovery-manifest encoding; PatchSet::plan then validates the exact current workspace tuple.
Both are independent of filesystem I/O. The returned PatchPlan is the only value accepted by the
transaction adapter. Content digests are recalculated from supplied final bytes, and an oversized
observed preimage is never represented by a synthetic matching digest.
Patch transactions use a protected transaction root separate from the agent-visible workspace. The root is a dedicated canonical namespace bound to the exact workspace, resource, and environment; it cannot contain or be contained by the worktree or Git common directory. The transaction identifier derives from the stable patch identity. Application proceeds through explicit phases:
- Re-read and validate every expected preimage.
- Write every final file under the transaction staging directory.
- Flush staged files and persist the complete transaction manifest with a canonical checksum over every recovery-semantic byte.
- Move existing targets to transaction backups.
- Install staged finals or apply deletions.
- Sync affected directories and re-read every requested result.
- Mark the transaction installed and remove recovery material only after verification.
An ordinary failure rolls completed operations back in reverse order. If rollback itself cannot be confirmed, the result is recovery-required rather than success.
recover_transaction requires an expected RecoveryBinding containing workspace, generation, and
revision, then validates the versioned manifest, required backups, and actual targets. It
reports an exact RecoveryOutcome: applied, rolled back, dirty, or indeterminate. When a manifest
decodes, RecoveryOutcome::binding exposes its observed binding. A binding mismatch is
indeterminate and performs no workspace or transaction mutation. Manifest integrity is verified
before any path or operation field is interpreted. Corrupt metadata is quarantined,
and directories created by an interrupted transaction are removed only when exact rollback can
prove that they are empty. Recovery can be repeated after another interruption.
WorkspaceBinding joins the configured WorkspaceId, ResourceId, and EnvironmentId to one
canonical worktree root and immutable baseline. The registered worktree separately carries its
repository identity. WorkspaceState additionally binds the current snapshot, Generation,
RevisionNumber, prior lease holder, WorkspaceCondition, and the consumed-action projection for
the current revision.
The API distinguishes WritableWorkspace from ReadOnlyWorkspace. A read-only snapshot is fixed
to one immutable snapshot identity and exposes inspection only. It has no patch, candidate, or
rollback method. Writable handles are move-only and owned by one WorkspaceGateway.
WorkspaceGateway is the only authority-bearing, product-facing mutation surface. The leaf Git
and patch adapters expose checked effects but grant no authority. A caller supplies a
WorkspaceAuthorizationRequest borrowing the exact post-commit observations already returned by
C0:
CommittedKernelTransition, containing B0's exact committed successor aggregate/action;CommittedCapabilityUse, containing B1's exact consumed capability transition; andCommittedLeaseTransition, containing B1's exact committed active lease-use transition.
The gateway cross-checks the requested action against the supplied committed B0 action phase,
action ID and digest, actor, role, environment, RevisionTuple, resource, and capability witness.
It then checks the committed capability transition and lease transition name the same action,
resource, workspace, environment, holder, generation, and current authority observation.
After every comparison succeeds, the writable target exclusively writes and synchronizes a
bounded action-consumption marker before constructing the crate-private, move-only
MutationPermit. Each marker binds the workspace, resource, environment, generation, revision,
action ID, and action digest under the separate transaction root. Writable reopen validates and
reloads the current revision's markers, so rebuilding a gateway does not reset receipt consumption.
The permit is consumed inside the requested target operation and is never returned or exported.
Raw B1 values, logical lease claims, uncommitted CAS observations, decoded B3 values, booleans, and
caller-created structs cannot substitute for the exact committed observations.
The gateway checks authority and durably records consumption immediately before the first target Git/filesystem effect. A workspace generation/revision change or any mismatch among the supplied committed authority facts rejects the request instead of applying it to a different state.
The normal writable sequence is:
- Open a writable workspace from an immutable
Baselineand exactWorkspaceBinding. - Obtain current B0/B1 transitions and commit them through C0.
- Build
WorkspaceAuthorizationRequestfrom those exact move-only observations. - Submit a checked
PatchSettoWorkspaceGateway. - Let the gateway authorize, plan, and transactionally apply the patch; the workspace is now
Dirtywhile its prior snapshot remains the durable current revision. - Obtain separate committed authority for candidate creation, then reconcile the exact
MutationOutcome, write its tree, and retain its C1 snapshot ref. - Canonically encode the workspace candidate manifest and finalize it through
ArtifactStore; only then install the successor revision asClean. - Pass the move-only
MutationOutcomeorCandidateOutcometo later orchestration for the matching B0/C0 completion transition.
The finalized workspace manifest directly binds its kind, workspace ID, generation,
previous/successor revision, authorizing action ID and digest, resulting tree, and a subordinate
detail digest. For a candidate, that detail digest combines the installed patch-manifest digest
with the Git candidate-manifest digest; the latter binds the exact status observations. The
move-only CandidateOutcome separately exposes the PatchIdentity, retained snapshot, canonical
workspace manifest, and finalized artifact identity. Finalization does not make the candidate
accepted.
RollbackRequest names a retained snapshot and a successor SnapshotId; the authorization
request is supplied separately to the gateway. The gateway rejects another workspace lineage,
restores the snapshot tree, reconciles all files and Git state, advances to a new logical revision,
and finalizes a rollback manifest. Once restoration has changed the worktree, any later failure
leaves the logical condition dirty for explicit reconciliation.
Rollback never changes the immutable baseline and never deletes the abandoned candidate tree, snapshot ref, or evidence. Content may match an earlier snapshot while the logical revision remains a new successor.
WorkspaceGateway::reconcile_restart takes the expected B1 ReconciliationCorrelation, derives
the observed correlation from target-owned workspace state, recovers every restart-visible patch
transaction with the exact current RecoveryBinding, and inspects Git against the baseline and
current snapshot tree. The durable action-consumption ledger is skipped because it is target
metadata rather than a patch transaction. Only exact txn- plus 64-lowercase-hex directories are
passed to patch recovery; unrelated namespace entries are hashed as dirty evidence without being
renamed or quarantined. C1 hashes the transaction and Git detail digests into
ReconciliationEvidence and classifies the result as:
Cleanwhen correlation is exact, no transaction is unresolved, and Git/filesystem state matches the committed snapshot;Dirtywhen definite tracked, untracked, ignored, conflict, or interrupted-patch changes exist;Fencedwhen the requested correlation differs in workspace scope, fenced generation, or prior holder; orIndeterminatewhen required Git/filesystem facts cannot be established.
C1 does not claim that a prior process holder is quiescent. C2 supplies that independent evidence
before B1 can combine a Clean resource observation into SafeToAcquire.
Each crate exposes an error code/kind, operation, recovery class, and bounded diagnostic context. Common recovery classes distinguish caller correction, retry, reopen/reconcile, rollback/recover, manual inspection, and terminal corruption. Expected malformed input and normal Git/filesystem failures return errors rather than panicking.
Important failure outcomes include:
- repository/object/worktree mismatch;
- malformed Git protocol output;
- dirty or conflicted worktree;
- invalid, protected, or symlink path;
- stale workspace generation/revision;
- preimage or final digest mismatch;
- patch rollback failure or interrupted transaction;
- B0/B1/C0 authorization mismatch;
- stale or fenced lease; and
- dirty or indeterminate restart state.
C1 owns three architecture refinements:
REF-C1-B1-RESOURCE-IDENTITY: resolved targets, capability permissions, lease scope, B0 witness, and workspace binding name the exact sameResourceId.REF-C1-B1-RECONCILE-SAFETY: only an exactly correlated and complete clean observation can produce the resource-safety half ofSafeToAcquire; dirty/unknown observations stay non-safe.REF-C1-B1-AUTHORITY-GATE: only the target-owned gateway can construct and consume its private mutation permit after exact current committed observations match.
The corresponding named Verus rules and executable refinement tests are registered in
verification/obligations.toml before the reservations are removed from architecture.toml.
Focused development checks are:
cargo test --package peritus-git --package peritus-patch --package peritus-workspace --all-targets --all-features --locked
cargo clippy --package peritus-git --package peritus-patch --package peritus-workspace --all-targets --all-features --locked -- -D warnings
RUSTDOCFLAGS="-D warnings" cargo doc --package peritus-git --package peritus-patch --package peritus-workspace --all-features --no-deps --locked
cargo verus verify --package peritus-git --package peritus-patch --package peritus-workspace --all-features --locked --check-toolchain --fwd-verus-args-to roots -- --no-cheating --rlimit 20
cargo test --package peritus-conformance --all-targets --all-features --locked
just gate-a
Integration tests use real temporary repositories, detached worktrees, files, symlinks where the platform supports them, Git candidate objects, artifact directories, C0 stores, deterministic A2 identities, and named fault points. No mock is accepted as evidence for Git/file effects or durable authorization receipts.