The v0.2 Reset: Plain and Managed Instead of a Universal Control Plane
The archived “v0.2” design line initially used C2 view-local RPM hardlinks. That was a real development implementation, but it was replaced by the single-payload design before the final v0.2.0 tag. The released v0.2.0 layout already used one canonical Pool and metadata-only views.
Several archived v0.2/v0.3 files nevertheless say “v0.2.0” used C2 hardlinks. They were written before the tag existed and used “v0.2.0” for the planned build. The delivered boundary is defined by the final 0.2.0 Changelog, release note, and source tag, all of which record one canonical Pool and metadata-only views.
On 2026-07-31, immediately after sealing the v0.1 source baseline, SOW began a product reset. The objective was not to salvage every V1 subsystem. It was to identify the smallest repository product that could replace Pigsty’s daily package-build workflow while keeping the safety lessons already learned.
The result was a boundary that still defines SOW: Plain for rebuildable directories, and Managed for long-lived repository ownership.
Why reset instead of incrementally simplifying V1
The v0.1 model had coupled five different jobs:
- build valid APT/YUM/asset repositories;
- maintain package history and snapshots;
- migrate a large legacy Pigsty topology;
- publish to multiple cloud/CDN targets;
- enforce commercial Edge access.
Removing one feature at a time would leave the same Git/CAS/Route ownership model in place. The reset instead asked which facts the core repository engine truly needed to own.
The initial phase-one boundary was as important as the feature list:
- no V1 Git database, Route/Manifest/Quarantine model, or global content-addressed product layer;
- no upstream sync, pull/push/copy/move/promote surface, Edge entitlement, CDN bootstrap, or commercial topology;
- no remote publication/state, object storage, GC, snapshot/freeze, Managed export, or serving in the first phase;
- no modulemd, source-package building, Web UI, cross-Repository deduplication, or multi-writer operation.
Upstream synchronization and channel promotion were deliberately removed even though V1 had real streaming, fuzz, and deterministic-proof evidence for them. Package acquisition is an input boundary, not a second owner inside the repository engine. Operators can prepare package sets with dedicated mirror or download tooling, then let SOW own admission, membership, build, and publication. Some phase-one exclusions—publication, retention, GC, and external export—returned before the final v0.2.0 tag under the smaller Repository ownership model.
Two isolated execution modes
Plain: rebuild what the caller owns
Plain mode operates on a caller-owned directory of RPM and DEB files:
It scans packages, renders protocol metadata, validates the result, and installs pointers last. Plain owns its generated metadata but not a Workspace, Repository database, Generation history, or long-lived membership state.
Because the desired state is simply “the packages currently in this directory,” the correct recovery strategy is to rerun the build. Later releases made that principle even more explicit by removing Plain journals and repeated package reads.
Managed: own lifecycle and history
Managed mode introduces a Workspace with independent Repositories:
Each Repository owns its Pool, Package Objects, Membership, Desired State, Built Generation, Changeset, lock, database, and recovery state. Different Repositories do not silently deduplicate or share counters.
A Dist is a named RPM or DEB membership set. Architecture Views are projections of that
membership, not new owners. Neutral packages (noarch / all) project into every
applicable architecture without duplicating logical membership.
Decisions that replaced V1 concepts
| V1 concept | v0.2 replacement |
|---|---|
| Git commit/ref as canonical state | Per-Repository SQLite plus explicit filesystem/journal evidence |
| Global CAS and Route materialization | Repository-owned Pool and protocol views |
| View/Snapshot/Stable ref graph | Dist membership, Desired revision, Built Generation, retained state |
| One universal command surface | Closed Plain and Managed CLI contracts |
| Implicit legacy topology | Strict sow.yml plus explicit names and selectors |
| Cross-product publication saga | Repository build kept separate from target publication |
| Reuse V1 packages directly | Narrow parser/renderer/version/signing ports only |
The critical simplification was that private control state and public repository bytes could be understood without Git or an Edge router.
Desired versus Built
Managed mode made interrupted state explicit:
- Desired State is the current package and membership intent in SQLite.
- Built Generation is the last complete public tree that rendered and validated successfully.
- Changeset is the exact delta between two built states.
Desired may advance while Built remains valid. A failed build therefore does not require pretending that the public tree changed or that the request never happened. Operation journals and status expose the difference.
This distinction survived every later release.
P0 through P3
The work was intentionally sequenced:
| Phase | Contract |
|---|---|
| P0 | Plain create, real RPM/DEB metadata, signing, Pigsty-compatible filtering, pointer-last replacement |
| P1 | Workspace/Repository/Dist lifecycle, strict config, package identity, membership, and query |
| P2 | Add/remove/policy/build operations, journals, crash recovery, and safe mutation |
| P3 | Check, Changeset, handoff, scale, compatibility, and clean-delivery evidence |
Each phase had an API contract, implementation specification, adversarial review, and traceability/acceptance record. Those documents were useful while building the release; their lasting decisions are summarized here rather than published as separate authorities.
The C2 hardlink detour
The first Managed RPM layout kept canonical files in a root Pool and added hardlinks below
each architecture View. Metadata used a safe local pool/... href. This C2 layout made a
pinned AlmaLinux 9 reposync flow work and avoided duplicate local bytes because aliases
shared an inode.
The design had a hidden deployment cost:
- object storage expands each path into a separate full object;
- archive and cross-filesystem copies can lose hardlink identity;
- every Dist/architecture alias looks like another canonical payload;
- retention and GC risk depending on inode/link-count behavior;
- the whole Repository no longer maps one-to-one to static object keys.
The pre-release design snapshot on 2026-08-05 accurately records C2 implementation and local acceptance. It is not the final v0.2.0 release contract.
The single-payload contract was written on 2026-08-05, committed as the “next” design on August 7, and implemented before the August 8 release tag. The final release therefore shipped:
Default EL reposync became an accepted compatibility limitation; a standalone RPM leaf
moved to an explicit external export. The complete reasoning is preserved in
Single-Payload Repository.
What the reset reused
The team did not start from blank code. It retained only narrow components that had no V1 ownership assumptions:
- RPM/DEB parsing and native version comparison;
- metadata rendering, compression, signing, and validation;
- safe filesystem primitives;
- selected client fixtures and fault patterns;
- exact package identity and provenance checks.
Git state, Route receipts, Edge components, legacy migration machinery, and cloud control plane code were reference material or removal candidates, not dependencies of the new core.
Release evidence boundary
The development line recorded P0/P1 acceptance on August 1, P1–P3 acceptance on August 2, and a local release-gate run on August 5. The final v0.2.0 source was tagged on August 8 after the single-payload implementation, packaging, and CI corrections landed.
The final release also shipped filesystem and R2 publication, retained generations, external RPM leaf export, and local GC. R2 remote deletion was disabled from the start and target GC retained/reporting candidates instead.
That distinction matters:
- an August 5 C2 PASS proves the development snapshot that produced it;
- the August 8 v0.2.0 tag and release note define what actually shipped;
- later v0.3/v0.4 tests do not rewrite either historical result.
What still defines SOW
- Plain and Managed are isolated modes with different recovery costs.
- Workspace is configuration/discovery scope; Repository is package/history scope.
- Package Object identity is immutable; Membership is logical and many-to-many.
- Desired and Built states are distinct.
- writes use stable locks, bounded journals, pointer-last installation, and fail-closed recovery;
- CLI syntax, JSON envelopes, and exit classes form a closed automation contract;
- protocol, client, mirror-tool, and provider compatibility are reported separately.
The current forms are documented in Get Started, System Model, and Design Principles.
Primary source snapshots
- v0.2 development design snapshot — PRD, API, C2 architecture, reviews, and local acceptance.
- single-payload “next” design — the contract adopted before the release tag.
- v0.2.0 release note and v0.2.0 source tag — the delivered product boundary.
Continue with Design Evolution for the v0.3 and v0.4 hardening that followed.
