Skip to content

SOW Design Evolution: From Route Graphs to the Repository Core

How SOW moved from the v0.1 distribution platform to a repository engine, and how v0.2 through v0.5 refined that model.

SOW moved from a Git-based distribution control plane in v0.1 to a repository engine in v0.2. This article traces that change and the refinements through v0.5.0.

Version numbers below refer to released Git tags. Some archived plans used “v0.2” and “v0.3” for development designs. In particular, the C2 layout with RPM hardlinks inside each view was replaced before v0.2.0 shipped.

Four articles cover the earlier work in detail:

The short history

Release Main changes Public layout
v0.1 Git/CAS state, Routes, Edge authorization, cloud workflows, and Pigsty migration Retired
v0.2 Plain/Managed modes, one package pool per Repository, metadata-only views, retained Generations, and target publication Introduced the current pool/ + dists/ layout
v0.3 Removed V1, cached package facts, simplified Plain builds, and batched payload commits Unchanged
v0.4 Single-pass verification, independent RPM trust rings, target rebind, and migration/recovery fixes Unchanged
v0.5 Package-path reservations, removal and recovery fixes, signing checks, and reproducible Plain timestamps Unchanged

The source tags preserve each implementation: v0.1.0, v0.2.0, v0.3.0, v0.4.0, and v0.5.0.

v0.1: useful questions, too many product concepts

The first plan covered Git-backed state, content-addressed storage, Routes and Views, snapshots, remote providers, Edge authorization, and legacy migration. Forty-four ADRs, numbered through 0045, documented the decisions and their failure cases.

The combined scope made ownership difficult to explain. Several objects could describe the same package bytes and published paths. Local repository generation also depended on cloud, Edge, and migration concepts.

The v0.2 reset removed Git as the authoritative product database, the separate CAS layer, the Route/View/Snapshot command model, and Edge access control. It made local repository construction the core task.

v0.2: establish a small ownership model

v0.2 split the product into two execution paths:

  • Plain scans a caller-owned directory and rebuilds RPM or DEB metadata in place.
  • Managed owns a Workspace containing independent Repositories. Each Repository has its own Pool, Dists, SQLite state, locks, and recovery records.

This reset introduced the terms still used today: Package Object, Membership, Desired and Built state, Generation, and Changeset. Stable lock files coordinate access. Generated files replace the protocol pointers last. Managed journals record how to recover an interrupted operation.

The first implementation, called C2, still placed package hardlinks in each RPM view. That layout changed before release.

v0.2.0: make Repository root the delivery unit

The single-payload decision was written on 2026-08-05 and shipped in v0.2.0 on August 8. It removed package aliases from RPM views. One Repository has one canonical pool/ and metadata-only dists/. The complete root is the unit to copy, host, authorize, and publish.

v0.2.0 also separated local and remote state:

  • Package Objects, Desired/Built state, Generations, Changesets, and local retention belong to the Repository.
  • Publication Attempts, Applied Checkpoints, remote inventories, cache grace, and deletion records belong to one Repository and one target prefix.

Repositories do not deduplicate packages across their boundaries. A target prefix has one owner. Compatibility exports are separate copies outside the canonical Repository.

v0.3: simplify and optimize the same model

v0.3 kept the v0.2.0 public layout. It removed the V1 runtime and migration harness, introduced the package-facts cache, and made Plain generation a rebuildable one-pass operation. It also expanded Membership in batches and grouped payload commits to reduce filesystem work.

v0.4: strengthen verification and recovery

v0.4 made Managed deep verification a bounded single pass. RPM verification must succeed within one trust ring; it cannot combine partial results from unrelated rings. An explicit rebind operation can update mutable target settings. Migration, publication recovery, and public-delivery checks also became stricter.

An early coordinated-publication proposal considered using rclone for bulk transfer. The final design kept native providers so SOW could check object identity, record receipts, control commit order, and recover publication from the same state machine.

v0.5: preserve package URLs and committed state

v0.5.0, released on 2026-09-29, kept the same public layout and upgraded managed state to schema 13. The new pool-path indexes prevent different package bytes from taking over an existing URL, including a URL recorded by an earlier publication.

The release also fixed recovery after Dist removal and package re-addition, preserved committed changes after interruption, and checked conflicting signing policies before changing Desired state. Plain create --metadata-timestamp added an explicit timestamp for reproducible RPM metadata; its default is zero. See the v0.5.0 changelog for the full changes.

What survived every redesign

Several v0.1 rules continue in the smaller model:

  • Give each durable fact one owner.
  • Keep package bytes separate from rebuildable metadata.
  • Prepare immutable payload and metadata before replacing protocol pointers.
  • After a durable commit intent, complete the operation through forward recovery.
  • Check references and exact identity before deletion. Remote deletion also checks cache grace and provider capabilities.
  • Record compatibility results with the source version, client, provider, and environment that produced them.

The current rationale is in Design Principles, System Model, Single-Payload Repository, and Publication & Recovery. Use SOW Docs for commands and operating procedures, and Release Notes for version-specific changes.