Transactions & Recovery
Managed mode records changes before it applies them. After an interruption, SOW uses these records to finish or roll back the operation. The recovery command depends on the operation that stopped.
Recover an interrupted operation
Start with the recorded state:
| State | Next step |
|---|---|
clean |
Run sow check before delivery |
dirty |
Run sow build to apply pending membership or configuration changes |
recovering |
Use the recovery command for the interrupted operation, listed below |
error |
Inspect the reported file or operation in the diagnostic and log |
| Interrupted operation | Recovery command |
|---|---|
add, rm, Dist change, or build |
sow build -r demo |
init, repo new, or repo rm |
Rerun the corresponding lifecycle command |
| Publication | sow publish TARGET |
| Plain index generation | Rerun sow create with the original options |
First correct any reported input, configuration, or storage error. Keep the workspace
configuration, database, and private state together during recovery. After a local recovery,
run sow check -r demo. See Troubleshooting for common errors
and publish for publication recovery.
What SOW records
| Record | Location | Purpose |
|---|---|---|
| Workspace lifecycle journal | .sow/workspace-ops/active.json |
Coordinates configuration with repository creation or removal |
| Repository operation journal | .sow/<repo>.db |
Records local membership changes, builds, and maintenance |
| Publication state | .sow/<repo>.db |
Records target bindings, frozen publication plans, and progress |
Workspace lifecycle recovery compares the current sow.yml digest with the journal’s old
and new configurations. The configuration replacement decides whether to roll back or
finish that lifecycle change. A digest matching neither is an integrity error.
Repository mutations record their own state transitions:
| State | Meaning |
|---|---|
planned |
The operation and its intended scope are recorded |
staged |
Inputs have been prepared for the next stage |
applied |
Desired state has committed; the previous public generation can still be active |
built |
The generated public tree has been installed |
done |
The operation is complete |
done_dirty |
Desired state has committed and a build remains pending |
Other terminal outcomes include rolled_back and failed. Read transitions and timestamps
with sow log OPERATION -r demo.
--skip normally ends at done_dirty. A recognized signing-policy change, configuration
change before a build plan is frozen, or supported contract upgrade can also leave a
committed operation dirty. The log records the reason. Correct the configuration if
needed, then run build again.
Errors after a committed change
Database commit and later maintenance are separate steps. A checkpoint or cleanup error can occur after package membership or a build has committed. SOW keeps the committed result in command output. It does not report those items as rolled back.
Read the result and sow status, then inspect the recorded operation with sow log.
Resume the command named in the diagnostic. Keep original input files until you have confirmed the result.
Local build order
SOW stages and validates output on the same filesystem, then applies it in this order:
- Put package bytes in the canonical
pool/path. - Install checksum-named RPM metadata and APT direct and by-hash indexes.
- Install RPM
repomd.xmland configured signatures, or APTRelease,InRelease, andRelease.gpgas applicable. - Remove obsolete metadata after the replacement is durable.
The build keeps the immediately preceding RPM immutable metadata and APT by-hash objects
available for readers of the previous pointer. Explicit generation retention is separate;
see retain.
A dirty repository still serves its last built generation. A multi-Dist operation can
switch views at different times. Remote HTTP requests and caches also have their own
lifetimes; use sow publish for live target updates. sow changes lists local file
changes and does not perform publication or target cleanup.
Locks and waiting
SOW uses advisory locks to coordinate its processes. Workspace lifecycle uses
.sow/workspace.lock; repository writes use .sow/repo-locks/<repo>.lock.
When both are required, the workspace lock comes first.
Read commands that need a consistent snapshot use shared locks. status probes the
repository writer lock so it can report activity without waiting for that writer.
Plain create locks its directory and parent.
| Option | Behavior |
|---|---|
-T 30s |
Wait up to 30 seconds for a write lock |
-T 0 |
Wait until the lock is available; default |
-N |
Try once; exit immediately if the lock is held |
A failed lock attempt exits 4. Combining -N with a nonzero -T exits 2.
Use only the lock options accepted by the command; read-only commands do not accept them.
Filesystem requirements
Use a local POSIX filesystem with advisory locks, fsync, and atomic rename. On macOS,
use APFS. Keep public files and private staging on the same filesystem. SOW rejects symlinked
control paths, unexpected file types, and path escapes. It checks file identity before
replacing or removing controlled objects. Network filesystems are not supported workspace
locations.
Repository and Dist names use [a-z0-9][a-z0-9._-]*; reserved names are listed in
Repository layout. For script responses to interruption, lock
contention, or integrity errors, see Exit codes.