Configuration transactions and recovery
Configuration transactions and recovery
WorkspaceMigrationService, ProjectMigrationService and ConfigurationEditService
apply through the shared ConfigurationTransaction boundary. Configuration tools
coordinate cooperating writers on one machine. They do not provide a distributed
lock, or a crash-atomic replacement of several files.
Batch application
A transaction first acquires writer coordination and checks pending recovery. It checks exact source and target bytes, observed absences, directory inventories and link topology. It creates durable write-ahead metadata before staging every candidate and original backup on the corresponding target filesystem. All stages, backups and preconditions must match before the first destination replacement. Artifact registration requires the predeclared deterministic path to have been absent before creation and its returned bytes to match the requested content. A host-returned path or matching transaction ID does not transfer ownership of an existing file or directory. Directory receipts must be a canonical subset of the parents observed missing in the plan.
The transaction rechecks remaining inputs between installations. Atomic native replacement protects one destination at a time.
If a replacement fails, the transaction attempts rollback in reverse order.
RestoredPaths identifies originals proven restored. UnresolvedPaths identifies
paths whose state is uncertain or whose bytes no longer match the recorded
original or candidate. The result retains artifact paths and their transaction
owner. Configuration bytes, backup bytes and secrets are never included in these
metadata results.
Written means the complete candidate was installed and its owned temporary
artifacts were cleaned. Unchanged leaves equivalent target bytes and timestamps
alone. Conflict means input evidence changed. RolledBack means rollback proved
the originals restored and cleaned transaction artifacts. RecoveryRequired
means retained evidence needs explicit inspection and recovery. Do not treat a
partial workspace, successful command exit from an unrelated tool, or the presence
of a candidate TOML file as evidence that the batch completed.
Inspect and recover through the shared API
Recovery is explicit. Keep the returned journal path and inspect it before taking action. Use the same authorized storage host that owns the paths:
var transaction = new ConfigurationTransaction(new NativeConfigurationTransactionHost());
var pending = transaction.InspectPending(new[] { workspaceRoot });
foreach (var item in pending)
{
Console.Error.WriteLine($"{item.JournalPath}: {item.Code}");
// Show item.Targets, item.Artifacts, item.UnresolvedPaths to the operator.
}
var inspection = transaction.InspectRecovery(journalPath);
if (inspection.Valid && inspection.UnresolvedPaths.IsEmpty)
{
// This call is an explicit recovery request by the host/operator.
var outcome = transaction.Recover(journalPath);
// Check outcome.Status and preserve outcome.Artifacts on RecoveryRequired.
}
Inspection does not change files. Recovery reacquires writer coordination and checks the metadata and file identities again. Without a valid committed witness, recovery restores the recorded originals. A target that was absent is removed only when its current bytes match this transaction’s candidate. With a durable committed witness, recovery verifies all installed candidates and finishes cleanup.
A host can stop between creating a directory and returning its ownership receipt.
Inspection reports these paths in UncertainDirectories. Default recovery keeps
the journal and returns RecoveryRequired. After reviewing those paths, an
operator can explicitly retain them as user-owned directories:
var result = transaction.Recover(journalPath, inspection.UncertainDirectories);
// Check result.Status. result.PreservedDirectories lists directories retained
// by this explicit request; transaction cleanup never claims or removes them.
This option accepts only the journal’s uncertain paths that remain regular directories. Linked paths, file replacements and unrelated paths remain blocked. It does not authorize deletion or discard user content.
If an adapter returns a foreign file or directory, or claims one in an exception, the live result reports that path as unresolved without claiming it as an owned artifact. A separate recovery journal records the rejected receipt. Explicit recovery preserves the unverified external paths, rolls back only verified owned changes, and removes only the transaction’s verified artifacts. A matching owner ID or filename prefix alone never authorizes moving, restoring or deleting a file.
If a target, backup, stage or journal has unexpected content or link topology,
recovery preserves it and reports an unresolved path. Live cleanup validates the
complete artifact set before deleting any artifact, then rechecks each artifact
immediately before deletion. Changing a backup or even reformatting a journal
therefore produces RecoveryRequired and retains the guard. Journal bytes must
match their canonical versioned encoding, including known roles and ownership
paths; whitespace, duplicate/unknown fields and role changes are not silently
normalized during recovery. Do not overwrite the user’s
new bytes with an old backup or delete evidence to bypass the guard. Preserve both
versions, review the metadata and restore a specifically approved state before
retrying recovery. Invalid/truncated journals need manual review; automatic
recovery does not invent metadata or infer ownership from a filename alone.
Journals and interruption windows
Native .morphir-edit-<transaction-id>-... files contain private stages, original
backups and metadata journals. Native creation uses exclusive new files and user
read/write permissions. Metadata and file bytes are flushed before proceeding.
Journals identify the complete target set, original and candidate hashes, stage
and backup paths, and guarded directories. They do not contain the source values.
The initial manifest is written in an existing common ancestor before any parent
directory creation. A durable directory receipt records directories whose creation
the host confirmed. The complete write-ahead manifest allows inspection after
interruption before a stage, between staging and replacement, or immediately after a replacement whose
callback did not return.
A committed witness distinguishes a completed installation from an interrupted commit. Cleanup preserves this witness until the other owned stages, backups and journals have been removed. An interruption during cleanup therefore remains identifiable. Complete success and complete rollback remove only owned temporary files and empty owned directories. An incomplete outcome retains journals and backups. Cooperating configuration and project/workspace editing paths refuse an overlapping write until explicit recovery resolves that state.
File flushes and atomic replacement do not promise group atomicity or recovery from every filesystem, storage-controller or power-loss failure. Uncooperative processes can modify files outside Morphir’s writer lock. Their unexpected bytes are treated as drift, not silently overwritten during recovery.
Custom storage hosts
IConfigurationTransactionHost remains the storage boundary. Hosts serialize
ordered canonical guarded paths across their writers, report exact byte hashes,
and atomically install one file. Writable hosts explicitly opt in with
SupportsDurableRecovery = true and implement FindRecoveryJournals and
EnumerateTransactionArtifacts. Enumeration must remain
bounded to authorized locations, include retained transaction-owned artifacts,
and never follow links. Stages and backups use
ConfigurationTransaction.GetArtifactPath(destination, transactionId, role);
recovery validates the owner, destination anchor and role, including when several
targets share identical bytes. Returning null for artifact enumeration means recovery
cannot prove cleanup completeness and returns config.recovery_host_capability.
Older adapters remain source compatible. Application refuses a host without this
capability before any write, returning IoFailure and
config.recovery_host_capability. Read-only planning remains available. Hosts
must add durable enumeration before opting into writes; an empty process-local
registry is not a substitute.
Recovery metadata uses version 2. Automatic recovery refuses unknown versions and invalid ownership. Preserve earlier journals for explicit review with their original host/version. Do not rewrite or silently delete them during an upgrade.
A lost host acknowledgement does not prove a commit failed. If the committed witness is present and validates against the attempted operation, application preserves the candidate files and backups and returns recovery required for explicit completion. If the witness is absent, rollback can proceed.
Rejected transaction-shaped artifacts remain recovery blockers while present. Recovery preserves the journals and reports their unresolved paths rather than claiming complete rollback with metadata left behind. Any manual disposition must first establish the artifact’s origin and preserve user changes. Unrelated foreign files are never cleanup authority.
If the storage host disconnects while a failure is being handled, application returns a typed recovery-required result with known or possible evidence locations and unresolved targets. Its fallback does not perform further storage observations or blind rollback. Reconnect storage and inspect the retained journal before explicitly recovering.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.