.nornir/assets/retention-executor-flow.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 860 380" 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}
.gate{fill:#78350f;stroke:#f59e0b}
.ware{fill:#1e3a8a;stroke:#3b82f6}
.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}
.gate{fill:#fef3c7;stroke:#d97706}.ware{fill:#dbeafe;stroke:#2563eb}
}
</style>
</defs>
<text x="20" y="26" class="lbl" font-size="15" font-weight="700">Retention / GC executor — planner decides, executor acts (gated + safe)</text>
<rect class="box" x="20" y="60" width="170" height="72" rx="8"/>
<text x="105" y="86" class="lbl" text-anchor="middle" font-weight="700">RetentionPlan</text>
<text x="105" y="104" class="sub" text-anchor="middle">delete-set + reasons</text>
<text x="105" y="119" class="sub" text-anchor="middle">(the planner's decision)</text>
<rect class="box gate" x="230" y="52" width="180" height="88" rx="8"/>
<text x="320" y="76" class="lbl" text-anchor="middle" font-weight="700">GcOptions</text>
<text x="320" y="96" class="sub" text-anchor="middle">dry_run = true (default)</text>
<text x="320" y="112" class="sub" text-anchor="middle">→ preview, drop nothing</text>
<text x="320" y="128" class="sub" text-anchor="middle">execute() = opt-in reclaim</text>
<rect class="box" x="450" y="44" width="200" height="104" rx="8"/>
<text x="550" y="68" class="lbl" text-anchor="middle" font-weight="700">execute_repo_retention</text>
<text x="550" y="88" class="sub" text-anchor="middle">skip kept + protected rows</text>
<text x="550" y="104" class="sub" text-anchor="middle">fetch bytes → sha-256</text>
<text x="550" y="120" class="sub" text-anchor="middle">verify content id, then</text>
<text x="550" y="136" class="sub" text-anchor="middle">delete_artifact() (unlink)</text>
<path class="edge" d="M190,96 L226,96" marker-end="url(#arw)"/>
<path class="edge" d="M410,96 L446,96" marker-end="url(#arw)"/>
<rect class="box drop" x="700" y="52" width="140" height="48" rx="8"/>
<text x="770" y="72" class="lbl" text-anchor="middle" font-weight="700">RECLAIMED</text>
<text x="770" y="90" class="sub" text-anchor="middle">bytes unlinked</text>
<rect class="box keep" x="700" y="116" width="140" height="48" rx="8"/>
<text x="770" y="136" class="lbl" text-anchor="middle" font-weight="700">REFUSED / SKIP</text>
<text x="770" y="154" class="sub" text-anchor="middle">id mismatch · protected</text>
<path class="edge" d="M650,84 L696,76" marker-end="url(#arw)"/>
<path class="edge" d="M650,112 L696,136" marker-end="url(#arw)"/>
<rect class="box ware" x="330" y="210" width="320" height="70" rx="8"/>
<text x="490" y="236" class="lbl" text-anchor="middle" font-weight="700">Historize → warehouse (append-only audit)</text>
<text x="490" y="256" class="sub" text-anchor="middle">AuditAction::Delete · reclaimed bytes · reasons</text>
<text x="490" y="272" class="sub" text-anchor="middle">Arrow IPC — the skade analysis-plane GC record</text>
<path class="edge" d="M560,148 C540,175 520,185 500,206" marker-end="url(#arw)"/>
<rect class="box" x="700" y="210" width="140" height="70" rx="8"/>
<text x="770" y="236" class="lbl" text-anchor="middle">jera job</text>
<text x="770" y="254" class="sub" text-anchor="middle">retention-gc</text>
<text x="770" y="270" class="sub" text-anchor="middle">running→done|failed</text>
<path class="edge" d="M650,245 L696,245" marker-end="url(#arw)"/>
<text x="20" y="326" class="sub">Gated: dry-run is the default; an actual reclaim is an explicit opt-in. A kept / protected-latest generation is never dropped.</text>
<text x="20" y="344" class="sub">Safe: every delete is content-id verified against on-disk bytes before the unlink — a store changed under the plan is refused.</text>
<text x="20" y="362" class="sub">Reuse: the run rides the same jera job ledger promotion uses; the reclaim is historized to the audit warehouse (skade).</text>
</svg>