Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

.nornir/assets/retention-flow.svg

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 820 360" font-family="ui-sans-serif,system-ui,sans-serif" font-size="13">
  <defs>
    <marker id="arw" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto" markerUnits="strokeWidth">
      <path d="M0,0 L7,3 L0,6 Z" fill="#64748b"/>
    </marker>
    <style>
      .box{fill:#0f172a;stroke:#334155;stroke-width:1.5}
      .lbl{fill:#e2e8f0}
      .sub{fill:#94a3b8;font-size:11px}
      .keep{fill:#065f46;stroke:#10b981}
      .drop{fill:#7f1d1d;stroke:#ef4444}
      .edge{stroke:#64748b;stroke-width:1.5;fill:none}
      @media (prefers-color-scheme: light){
        .box{fill:#f1f5f9;stroke:#cbd5e1}
        .lbl{fill:#0f172a}.sub{fill:#475569}
        .keep{fill:#d1fae5;stroke:#059669}.drop{fill:#fee2e2;stroke:#dc2626}
      }
    </style>
  </defs>

  <text x="20" y="26" class="lbl" font-size="15" font-weight="700">Retention / GC planner — a pure function over artifact metadata</text>

  <rect class="box" x="20" y="60" width="160" height="66" rx="8"/>
  <text x="100" y="86" class="lbl" text-anchor="middle">backend.list()</text>
  <text x="100" y="104" class="sub" text-anchor="middle">ArtifactRecord[]</text>
  <text x="100" y="118" class="sub" text-anchor="middle">id · size · created_at?</text>

  <rect class="box" x="220" y="60" width="160" height="66" rx="8"/>
  <text x="300" y="86" class="lbl" text-anchor="middle">group by</text>
  <text x="300" y="104" class="sub" text-anchor="middle">(namespace, name)</text>
  <text x="300" y="118" class="sub" text-anchor="middle">newest-first / version</text>

  <rect class="box" x="420" y="52" width="180" height="120" rx="8"/>
  <text x="510" y="76" class="lbl" text-anchor="middle" font-weight="700">plan_retention()</text>
  <text x="510" y="96" class="sub" text-anchor="middle">protect_latest_per_name</text>
  <text x="510" y="112" class="sub" text-anchor="middle">keep_min_per_name (floor)</text>
  <text x="510" y="128" class="sub" text-anchor="middle">keep_last_n</text>
  <text x="510" y="144" class="sub" text-anchor="middle">max_age_secs</text>
  <text x="510" y="160" class="sub" text-anchor="middle">max_total_bytes (quota)</text>

  <rect class="box keep" x="650" y="60" width="150" height="52" rx="8"/>
  <text x="725" y="82" class="lbl" text-anchor="middle" font-weight="700">KEEP</text>
  <text x="725" y="99" class="sub" text-anchor="middle">+ keep reasons</text>

  <rect class="box drop" x="650" y="128" width="150" height="52" rx="8"/>
  <text x="725" y="150" class="lbl" text-anchor="middle" font-weight="700">RECLAIM</text>
  <text x="725" y="167" class="sub" text-anchor="middle">superseded / aged / quota</text>

  <path class="edge" d="M180,93 L216,93" marker-end="url(#arw)"/>
  <path class="edge" d="M380,93 L416,100" marker-end="url(#arw)"/>
  <path class="edge" d="M600,100 C625,92 625,90 646,86" marker-end="url(#arw)"/>
  <path class="edge" d="M600,120 C625,132 625,140 646,150" marker-end="url(#arw)"/>

  <rect class="box" x="220" y="230" width="380" height="70" rx="8"/>
  <text x="410" y="256" class="lbl" text-anchor="middle" font-weight="700">RetentionPlan (decision only — deletes nothing)</text>
  <text x="410" y="276" class="sub" text-anchor="middle">kept_count · delete_count · kept_bytes · reclaimed_bytes</text>
  <text x="410" y="292" class="sub" text-anchor="middle">per-artifact verdict + reasons · deterministic order</text>

  <path class="edge" d="M510,172 L440,226" marker-end="url(#arw)"/>

  <rect class="box" x="650" y="230" width="150" height="70" rx="8"/>
  <text x="725" y="256" class="lbl" text-anchor="middle">carried out by</text>
  <text x="725" y="274" class="sub" text-anchor="middle">a jera job (drop</text>
  <text x="725" y="288" class="sub" text-anchor="middle">superseded archives)</text>
  <path class="edge" d="M600,265 L646,265" marker-end="url(#arw)"/>

  <text x="20" y="330" class="sub">Pure + deterministic: same (records, policy, now) ⇒ same plan. No I/O, no scheduler, no deletion — the plan IS the decision.</text>
  <text x="20" y="348" class="sub">Immutable znippy archives ⇒ retention is archive-set level; the drop is a delegated jera job, the decision historized to skade.</text>
</svg>