<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:fh="http://purl.org/syndication/history/1.0" xmlns:nimpress="https://github.com/nimling/nimpress">
  <channel>
    <title>Changelog</title>
    <link>https://developer.samna.io/tools/smig/changelog</link>
    <description>Samna developer documentation</description>
    <atom:link href="https://developer.samna.io/tools/smig/changelog/rss.xml" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Thu, 02 Jul 2026 00:00:00 GMT</lastBuildDate>
    <ttl>1440</ttl>
    <sy:updatePeriod>daily</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <nimpress:releaseCadence>86400</nimpress:releaseCadence>
    <nimpress:latestVersion>1.3.12</nimpress:latestVersion>
    <nimpress:releaseCount>4</nimpress:releaseCount>
    <item>
      <title>v1.3.12 Stable git include identities</title>
      <link>https://developer.samna.io/tools/smig/changelog#v1.3.12</link>
      <guid isPermaLink="true">https://developer.samna.io/tools/smig/changelog#v1.3.12</guid>
      <pubDate>Thu, 02 Jul 2026 00:00:00 GMT</pubDate>
      <description>A git include file is identified by its path inside the source repo, so up matches it across runs and destroy then up rebuilds cleanly.</description>
      <content:encoded><![CDATA[<h2 id="git-include-files-keep-a-stable-identity" tabindex="-1"><a class="header-anchor" href="#git-include-files-keep-a-stable-identity"><span>Git include files keep a stable identity</span></a></h2>
<p>A git include step clones into a throwaway temp dir that changes every run, and a file's identity was taken relative to that temp dir. The stored path in the ledger from one run could never be matched by the next run, so <code>up</code> failed with <code>step not found</code> for any git included file whenever the ledger already held a path from an earlier run.</p>
<p>A file's identity is now taken relative to the fetched source root, so a git include file is identified by its path inside the source repo, such as <code>prophet/database/V1.0__claimius_roles.sql</code>, independent of the throwaway clone dir. Local includes are unchanged and stay relative to the db dir. The right base is detected from the include itself, so no extra config is needed. The clone is still fetched once per run and reused, and <code>up</code> reads a file's bytes from the resolved clone path rather than reconstructing it from the identity.</p>
<p>With stable identities the ledger matches across runs on any machine, so <code>up</code> no longer reports <code>step not found</code>, and <code>destroy</code> then <code>up</code> rebuilds a database cleanly.</p>
]]></content:encoded>
    </item>
    <item>
      <title>v1.3.11 Relative db-dir and a cleaner destroy</title>
      <link>https://developer.samna.io/tools/smig/changelog#v1.3.11</link>
      <guid isPermaLink="true">https://developer.samna.io/tools/smig/changelog#v1.3.11</guid>
      <pubDate>Wed, 01 Jul 2026 00:00:00 GMT</pubDate>
      <description>Git include steps resolve under a relative db-dir, and destroy drops the ledger, skips extension owned objects, and can drop extensions on request.</description>
      <content:encoded><![CDATA[<p>Two fixes make everyday runs safer.</p>
<h2 id="relative-db-dir-with-git-include-steps" tabindex="-1"><a class="header-anchor" href="#relative-db-dir-with-git-include-steps"><span>Relative db-dir with git include steps</span></a></h2>
<p>A git include step clones into an absolute temp dir, so the ledger has to store a path that resolves back later. Path handling is now absolute safe end to end: the stored file path is derived from absolute forms of both the db dir and the clone, and every reconstruction that reads a file back joins the db dir only when the stored path is relative. A relative <code>--db-dir</code> such as <code>./database</code> now works with git include steps instead of failing with a file missing on disk.</p>
<h2 id="destroy-drops-the-ledger-and-skips-extension-owned-objects" tabindex="-1"><a class="header-anchor" href="#destroy-drops-the-ledger-and-skips-extension-owned-objects"><span>Destroy drops the ledger and skips extension owned objects</span></a></h2>
<p><code>destroy</code> now leaves the target in a truly clean state.</p>
<ul>
<li>Objects owned by an extension, such as the functions <code>pgcrypto</code> installs, are excluded from the plan so the individual drops do not fail.</li>
<li>The <code>samna_migrate</code> ledger is always dropped with <code>DROP SCHEMA samna_migrate CASCADE</code>, so a following <code>up</code> re-applies from scratch.</li>
<li><code>--extensions</code> adds <code>DROP EXTENSION &lt;name&gt; CASCADE</code> for every extension the tree creates. <code>plpgsql</code> is never dropped.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>v1.3.10 Dump insert and destroy</title>
      <link>https://developer.samna.io/tools/smig/changelog#v1.3.10</link>
      <guid isPermaLink="true">https://developer.samna.io/tools/smig/changelog#v1.3.10</guid>
      <pubDate>Wed, 01 Jul 2026 00:00:00 GMT</pubDate>
      <description>Export table data to json, load it back, and tear a database down to exactly what the tree creates.</description>
      <content:encoded><![CDATA[<p>Three commands round out working with the data and the objects a tree owns.</p>
<h2 id="dump-table-data-to-json" tabindex="-1"><a class="header-anchor" href="#dump-table-data-to-json"><span>Dump table data to json</span></a></h2>
<p><code>dump</code> writes the rows of each selected table to <code>&lt;schema&gt;.&lt;table&gt;.json</code>, limited to the base tables in the schemas declared by <code>migrate.yml</code>. <code>--all</code> takes every such table, <code>--table=&lt;schema.table&gt;</code> a subset, <code>--out=&lt;dir&gt;</code> the destination. With no selection flag and a terminal it opens an arrow key list. Postgres encodes each file with <code>jsonb_agg(to_jsonb(...))</code>, so uuid, numeric, jsonb, and timestamptz round trip exactly.</p>
<h2 id="insert-rows-back" tabindex="-1"><a class="header-anchor" href="#insert-rows-back"><span>Insert rows back</span></a></h2>
<p><code>insert</code> loads those files back into their tables. Point it at a folder or individual files; the target table is read from each file name and rows load through <code>jsonb_populate_recordset</code> so every column is typed from the table itself. <code>--no-triggers</code> disables user triggers on the table for the load.</p>
<h2 id="destroy-what-the-tree-creates" tabindex="-1"><a class="header-anchor" href="#destroy-what-the-tree-creates"><span>Destroy what the tree creates</span></a></h2>
<p><code>destroy</code> builds the tree into a throwaway Postgres, inventories exactly the objects those files produce, and drops that set from the live server: declared schemas other than <code>public</code> with <code>DROP SCHEMA CASCADE</code>, objects in <code>public</code> one by one with <code>DROP ... IF EXISTS CASCADE</code>. It then resets <code>samna_migrate.file</code> so a following <code>up</code> re-applies from scratch. The plan is printed and the database name is required to confirm.</p>
<ul>
<li><code>destroy</code> needs docker for the candidate build, and objects in <code>public</code> the tree does not create are left untouched.</li>
<li><code>--dry-run</code> prints the plan and drops nothing.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>v1.3.3 Clear orphaned ledger entries</title>
      <link>https://developer.samna.io/tools/smig/changelog#v1.3.3</link>
      <guid isPermaLink="true">https://developer.samna.io/tools/smig/changelog#v1.3.3</guid>
      <pubDate>Mon, 29 Jun 2026 00:00:00 GMT</pubDate>
      <description>Migration rows whose file is absent from the tree can now be folded, clearing the boot blocker a history squash leaves behind.</description>
      <content:encoded><![CDATA[<p>A migration history squash folds the original migration files into the baseline and deletes them from the tree, but the live ledger still carries them as applied. The next <code>up</code> then aborts with <code>applied but absent from the source tree</code>. This release adds a focused way to reconcile that state.</p>
<h2 id="prune-orphaned-migration-entries" tabindex="-1"><a class="header-anchor" href="#prune-orphaned-migration-entries"><span>Prune orphaned migration entries</span></a></h2>
<p><code>rebase --prune</code> folds every applied migration row whose file is absent from the source tree, setting <code>state = 'folded'</code> and writing a <code>fold</code> history row per entry. It touches only orphaned migration entries and leaves pending files untouched, so a following <code>up</code> applies the genuinely new migrations with their SQL actually executing.</p>
<ul>
<li>Run <code>reconcile --db</code> first to confirm the tree still produces the folded migrations' objects against live.</li>
<li>The fold is reversible: it is recorded in history and reversed by restoring the source file.</li>
<li>A whole-tree <code>rebase</code> stamps pending files as applied without running their SQL, so <code>--prune</code> is the correct tool for orphaned entries.</li>
</ul>
]]></content:encoded>
    </item>
  </channel>
</rss>