<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Feature on SOW</title>
    <link>https://sow.pgsty.com/categories/feature/</link>
    <description>Recent content in Feature on SOW</description>
    <generator>Hugo</generator>
    <language>en</language>
    
    
    
      <lastBuildDate>Fri, 28 Aug 2026 18:32:04 +0800</lastBuildDate>
    
    
      <atom:link href="https://sow.pgsty.com/categories/feature/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
        <title>Plain Flat Repositories</title>
        <link>https://sow.pgsty.com/docs/feature/plain/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://sow.pgsty.com/docs/feature/plain/</guid>
        <description>&lt;p&gt;&lt;code&gt;sow create&lt;/code&gt; takes a directory that already contains &lt;code&gt;.rpm&lt;/code&gt; and &lt;code&gt;.deb&lt;/code&gt; files and writes flat repository indexes beside them. Plain mode has no workspace, configuration file, database, desired state, or operation journal. The package directory is the authority; every index is a disposable projection of its current contents.&lt;/p&gt;&#xA;&lt;p&gt;That distinction is intentional. Managed repositories retain state and recover transactions. Plain repositories are cheap to recreate: if a run fails or is interrupted, run the same command again and overwrite the derived metadata.&lt;/p&gt;</description>
      </item>
    <item>
        <title>Features</title>
        <link>https://sow.pgsty.com/docs/feature/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://sow.pgsty.com/docs/feature/</guid>
        <description>&lt;p&gt;SOW has two isolated execution paths. Plain mode is a stateless rebuild of one directory;&#xA;Managed mode records package membership and immutable repository generations in a workspace.&#xA;Neither path silently adopts state from the other.&lt;/p&gt;&#xA;&lt;h2 id=&#34;capability-matrix&#34;&gt;Capability matrix&#xA;&lt;/h2&gt;&#xA;&lt;div class=&#34;td-table-scroll td-table-scroll--static&#34;&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;th scope=&#34;col&#34;&gt;Capability&lt;/th&gt;&#xA;      &lt;th scope=&#34;col&#34; style=&#34;text-align: right&#34;&gt;Plain&lt;/th&gt;&#xA;      &lt;th scope=&#34;col&#34; style=&#34;text-align: right&#34;&gt;Managed&lt;/th&gt;&#xA;    &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;RPM and DEB metadata&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;yes&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;yes&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Mixed RPM + DEB operation&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;one directory&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;one Repository, separate Dists&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Persistent membership and generations&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;yes&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Per-architecture views and neutral packages&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;yes&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;&lt;code&gt;exclude&lt;/code&gt; and version &lt;code&gt;limit&lt;/code&gt; policy&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;yes&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Metadata signing&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;RPM and DEB&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;RPM package signing&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;&lt;code&gt;--sign-with&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;&lt;code&gt;never&lt;/code&gt;, &lt;code&gt;fill&lt;/code&gt;, &lt;code&gt;always&lt;/code&gt;&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Transaction journal and recovery&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;rerun &lt;code&gt;create&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;workspace, Repository, publication&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Queryable operation log and JSONL export&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;yes&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Publication targets&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;filesystem and R2&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;p&gt;SOW parses packages and renders metadata in-process. It does not invoke&#xA;&lt;code&gt;createrepo_c&lt;/code&gt;, &lt;code&gt;dpkg-scanpackages&lt;/code&gt;, &lt;code&gt;reprepro&lt;/code&gt;, or &lt;code&gt;modifyrepo_c&lt;/code&gt;. RPM package signing&#xA;is the exception: it needs the host &lt;code&gt;rpm&lt;/code&gt; command and GPG environment because it rewrites&#xA;package payloads.&lt;/p&gt;</description>
      </item>
    <item>
        <title>Managed Workspaces</title>
        <link>https://sow.pgsty.com/docs/feature/managed/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://sow.pgsty.com/docs/feature/managed/</guid>
        <description>&lt;p&gt;Managed mode is what you use when the same repository will be updated for months: packages arrive in batches, policy decides what stays, and you need to prove afterwards what changed and when. This page explains the three-tier model, the layout it produces, and how commands figure out which repository and which Dist you meant.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-three-tiers&#34;&gt;The three tiers&#xA;&lt;/h2&gt;&#xA;&lt;div class=&#34;td-code td-code--untitled&#34; id=&#34;td-code-01e8acae-fence-0&#34; data-td-code data-td-code-auto-id&#xA;     data-td-language=&#34;text&#34; data-td-line-count=&#34;4&#34;&gt;&#xA;  &lt;div class=&#34;td-code__viewport&#34; id=&#34;td-code-01e8acae-fence-0-viewport&#34; data-td-code-viewport&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Workspace                          discovery and configuration boundary&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── Repository                     ownership boundary: pool, dists, SQLite, lock, generations&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    └── Dist                       a named membership set in exactly one format&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        └── Architecture View      a rendered projection — not a membership&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;Each tier has one job, and the boundaries are strict:&lt;/p&gt;</description>
      </item>
    <item>
        <title>Pool &amp; Metadata Views</title>
        <link>https://sow.pgsty.com/docs/feature/views/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://sow.pgsty.com/docs/feature/views/</guid>
        <description>&lt;h2 id=&#34;the-invariant&#34;&gt;The invariant&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Within one Repository, every live Package Object has one canonical payload path under&#xA;&lt;code&gt;pool/&lt;/code&gt;. Dists and architecture views own metadata, not aliases of package bytes:&lt;/p&gt;&#xA;&lt;div class=&#34;td-code td-code--untitled&#34; id=&#34;td-code-2e61d7a1-fence-0&#34; data-td-code data-td-code-auto-id&#xA;     data-td-language=&#34;text&#34; data-td-line-count=&#34;3&#34;&gt;&#xA;  &lt;div class=&#34;td-code__viewport&#34; id=&#34;td-code-2e61d7a1-fence-0-viewport&#34; data-td-code-viewport&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;repo&amp;gt;/pool/...                              canonical package payloads&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;repo&amp;gt;/dists/&amp;lt;rpm-dist&amp;gt;/&amp;lt;arch&amp;gt;/repodata/... RPM metadata only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;repo&amp;gt;/dists/&amp;lt;deb-dist&amp;gt;/main/binary-*/...   APT metadata only&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The same digest in another Repository or publication prefix is a separately owned object.&#xA;SOW deliberately does not turn local deduplication into shared distributed ownership.&lt;/p&gt;</description>
      </item>
    <item>
        <title>Membership Policy</title>
        <link>https://sow.pgsty.com/docs/feature/policy/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://sow.pgsty.com/docs/feature/policy/</guid>
        <description>&lt;p&gt;Policy is the answer to &amp;ldquo;I dumped a build directory into this Dist and I do not want the debuginfo packages, and I only want the latest version of each package.&amp;rdquo; Two rules do that work, they run in a fixed order, and they run over the whole candidate set — not just the packages you happened to add this time.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-two-rules-and-their-order&#34;&gt;The two rules and their order&#xA;&lt;/h2&gt;&#xA;&lt;div class=&#34;td-code td-code--untitled&#34; id=&#34;td-code-77527e0b-fence-0&#34; data-td-code data-td-code-auto-id&#xA;     data-td-language=&#34;text&#34; data-td-line-count=&#34;1&#34;&gt;&#xA;  &lt;div class=&#34;td-code__viewport&#34; id=&#34;td-code-77527e0b-fence-0-viewport&#34; data-td-code-viewport&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;candidate set  →  exclude  →  limit  →  Desired Membership&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;&lt;code&gt;exclude&lt;/code&gt; drops packages that match a rule. &lt;code&gt;limit&lt;/code&gt; then caps how many versions survive per package name and architecture. The order is fixed and never configurable, because the reverse order would let an excluded package consume a version slot on its way out.&lt;/p&gt;</description>
      </item>
    <item>
        <title>Signing Model</title>
        <link>https://sow.pgsty.com/docs/feature/signing/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://sow.pgsty.com/docs/feature/signing/</guid>
        <description>&lt;p&gt;There are two different questions a client can ask about a repository, and SOW answers them with two separate mechanisms. Confusing them is the most common source of &amp;ldquo;I signed it but &lt;code&gt;dnf&lt;/code&gt; still complains&amp;rdquo;, so this page starts by pulling them apart.&lt;/p&gt;&#xA;&lt;h2 id=&#34;two-independent-trust-chains&#34;&gt;Two independent trust chains&#xA;&lt;/h2&gt;&#xA;&lt;div class=&#34;td-table-scroll td-table-scroll--static&#34;&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;th scope=&#34;col&#34;&gt;&lt;/th&gt;&#xA;      &lt;th scope=&#34;col&#34;&gt;Metadata signing&lt;/th&gt;&#xA;      &lt;th scope=&#34;col&#34;&gt;RPM package signing&lt;/th&gt;&#xA;    &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Question answered&lt;/td&gt;&#xA;      &lt;td&gt;&amp;ldquo;Is this index really from you, and unmodified?&amp;rdquo;&lt;/td&gt;&#xA;      &lt;td&gt;&amp;ldquo;Is this &lt;code&gt;.rpm&lt;/code&gt; file really from you?&amp;rdquo;&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Configured by&lt;/td&gt;&#xA;      &lt;td&gt;&lt;code&gt;signing.rpm.metadata&lt;/code&gt;, &lt;code&gt;signing.deb.metadata&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;td&gt;&lt;code&gt;signing.rpm.packages&lt;/code&gt;&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Produces&lt;/td&gt;&#xA;      &lt;td&gt;&lt;code&gt;repodata/repomd.xml.asc&lt;/code&gt;, &lt;code&gt;InRelease&lt;/code&gt;, &lt;code&gt;Release.gpg&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;td&gt;an OpenPGP signature embedded in the package&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Changes package bytes&lt;/td&gt;&#xA;      &lt;td&gt;no&lt;/td&gt;&#xA;      &lt;td&gt;yes&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Client setting&lt;/td&gt;&#xA;      &lt;td&gt;dnf &lt;code&gt;repo_gpgcheck=1&lt;/code&gt;, apt &lt;code&gt;Signed-By&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;td&gt;dnf &lt;code&gt;gpgcheck=1&lt;/code&gt;&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;Available in Plain mode&lt;/td&gt;&#xA;      &lt;td&gt;no&lt;/td&gt;&#xA;      &lt;td&gt;yes, via &lt;code&gt;create -S KEY&lt;/code&gt;&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;p&gt;They are configured separately and can be used separately. Metadata signing alone is usually the right starting point: it authenticates the whole index in one place and requires no change to the packages you received from upstream.&lt;/p&gt;</description>
      </item>
    <item>
        <title>Transactions &amp; Recovery</title>
        <link>https://sow.pgsty.com/docs/feature/transactions/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://sow.pgsty.com/docs/feature/transactions/</guid>
        <description>&lt;p&gt;This page explains how Managed mode prevents a live pointer from naming missing content&#xA;and how it coordinates SQLite state with filesystem changes.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-invariant&#34;&gt;The invariant&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;On a supported local POSIX filesystem, a client following a Managed protocol pointer&#xA;reads a complete old view or a complete new view, including after interruption.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Everything below exists to hold that line: metadata is fully staged and verified before anything public moves, the pointer swap is the commit decision, and every operation records enough durable evidence that the next command can finish it or undo it without guessing.&lt;/p&gt;</description>
      </item>
    <item>
        <title>Observability &amp; Audit</title>
        <link>https://sow.pgsty.com/docs/feature/audit/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://sow.pgsty.com/docs/feature/audit/</guid>
        <description>&lt;p&gt;Each read surface answers a different question.&lt;/p&gt;&#xA;&lt;div class=&#34;td-table-scroll td-table-scroll--static&#34;&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;th scope=&#34;col&#34;&gt;Command&lt;/th&gt;&#xA;      &lt;th scope=&#34;col&#34;&gt;Question&lt;/th&gt;&#xA;      &lt;th scope=&#34;col&#34; style=&#34;text-align: right&#34;&gt;Writes?&lt;/th&gt;&#xA;    &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;td&gt;What state is the Repository in?&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;&lt;code&gt;check&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;td&gt;Does the selected Repository satisfy the complete delivery contract?&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;&lt;code&gt;changes&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;td&gt;What physical files differ between Built Generations?&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;&lt;code&gt;log&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;td&gt;Which operations and dispositions were recorded?&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;    &lt;tr&gt;&#xA;      &lt;td&gt;&lt;code&gt;retain ls&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;td&gt;Which Generations are explicit local GC roots?&lt;/td&gt;&#xA;      &lt;td style=&#34;text-align: right&#34;&gt;no&lt;/td&gt;&#xA;    &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;h2 id=&#34;status-cheap-state&#34;&gt;&lt;code&gt;status&lt;/code&gt;: cheap state&#xA;&lt;/h2&gt;&#xA;&lt;div class=&#34;td-code td-code--untitled&#34; id=&#34;td-code-e24b4625-fence-0&#34; data-td-code data-td-code-auto-id&#xA;     data-td-language=&#34;bash&#34; data-td-line-count=&#34;1&#34;&gt;&#xA;  &lt;div class=&#34;td-code__viewport&#34; id=&#34;td-code-e24b4625-fence-0-viewport&#34; data-td-code-viewport&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sow status -r local&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;It reports the Desired revision, Built Generation, dirty Dists, pending payload counts,&#xA;lock state, and &lt;code&gt;ready_to_copy&lt;/code&gt;. It does not hash the public tree, recover an operation, or&#xA;build.&lt;/p&gt;</description>
      </item>
    
  </channel>
</rss>
