.nornir/assets/read_delta_cdc.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1180 560" font-family="'DejaVu Sans', 'Segoe UI', sans-serif">
<defs>
<linearGradient id="board" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#0b1c2e"/>
<stop offset="1" stop-color="#06111d"/>
</linearGradient>
<linearGradient id="chip" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#14384f"/>
<stop offset="1" stop-color="#0e2a3e"/>
</linearGradient>
<linearGradient id="rail" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#173d57"/>
<stop offset="1" stop-color="#0c2438"/>
</linearGradient>
<linearGradient id="ice" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#e4f5ff" stop-opacity="0.95"/>
<stop offset="0.55" stop-color="#bfe6ff" stop-opacity="0.6"/>
<stop offset="1" stop-color="#bfe6ff" stop-opacity="0.08"/>
</linearGradient>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto">
<path d="M0,0 L7,3 L0,6 Z" fill="#7fd4ff"/>
</marker>
<marker id="arrowAmber" markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto">
<path d="M0,0 L7,3 L0,6 Z" fill="#ffcf7a"/>
</marker>
<marker id="arrowRed" markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto">
<path d="M0,0 L7,3 L0,6 Z" fill="#ff8b8b"/>
</marker>
</defs>
<!-- PCB substrate -->
<rect x="0" y="0" width="1180" height="560" fill="url(#board)"/>
<g stroke="#143a52" stroke-width="1">
<line x1="0" y1="70" x2="1180" y2="70"/>
<line x1="0" y1="516" x2="1180" y2="516"/>
</g>
<!-- Title -->
<text x="40" y="44" fill="#dff2ff" font-size="26" font-weight="700">read_delta(from, to)</text>
<text x="300" y="44" fill="#7fd4ff" font-size="17">— CDC over the Iceberg manifest layer · pure Rust · no Spark</text>
<text x="40" y="540" fill="#5d86a3" font-size="13">iceberg-rust 0.9.1 has no incremental/changelog scan (snapshot_id time-travel only) — skade reconstructs the delta from manifests.</text>
<!-- 1. Lineage walk -->
<rect x="40" y="110" width="300" height="150" rx="12" fill="url(#chip)" stroke="#2c6b94" stroke-width="1.5"/>
<text x="60" y="138" fill="#9fe3ff" font-size="15" font-weight="700">1 · lineage walk</text>
<text x="60" y="158" fill="#86b6d3" font-size="12">to → parent_snapshot_id() → from (excl.)</text>
<!-- snapshot chain -->
<g>
<circle cx="78" cy="210" r="16" fill="url(#rail)" stroke="#3b86b5"/>
<text x="78" y="215" fill="#cdeeff" font-size="12" text-anchor="middle">from</text>
<circle cx="168" cy="210" r="16" fill="url(#rail)" stroke="#3b86b5"/>
<text x="168" y="215" fill="#cdeeff" font-size="12" text-anchor="middle">s1</text>
<circle cx="258" cy="210" r="16" fill="url(#rail)" stroke="#3b86b5"/>
<text x="258" y="215" fill="#cdeeff" font-size="12" text-anchor="middle">s2</text>
<circle cx="312" cy="210" r="16" fill="#173d57" stroke="#7fd4ff" stroke-width="2"/>
<text x="312" y="215" fill="#dff2ff" font-size="12" text-anchor="middle">to</text>
<line x1="296" y1="210" x2="186" y2="210" stroke="#7fd4ff" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="242" y1="210" x2="186" y2="210" stroke="#7fd4ff" stroke-width="0"/>
<line x1="152" y1="210" x2="96" y2="210" stroke="#7fd4ff" stroke-width="1.5" marker-end="url(#arrow)"/>
</g>
<text x="60" y="248" fill="#86b6d3" font-size="11">new snapshots, oldest-first</text>
<!-- 2. Operation guard -->
<rect x="380" y="110" width="300" height="150" rx="12" fill="url(#chip)" stroke="#2c6b94" stroke-width="1.5"/>
<text x="400" y="138" fill="#9fe3ff" font-size="15" font-weight="700">2 · per-snapshot op guard</text>
<text x="400" y="166" fill="#bfe6ff" font-size="13">Append (inserts) ✓</text>
<text x="400" y="190" fill="#ffcf7a" font-size="13">Delete (equality deletes) ✓</text>
<text x="400" y="222" fill="#ff8b8b" font-size="13">Overwrite / Replace / PositionDeletes</text>
<text x="400" y="242" fill="#ff8b8b" font-size="13">→ needs_full_reload</text>
<!-- 3. Manifest-list scan / classify -->
<rect x="40" y="300" width="640" height="180" rx="12" fill="url(#rail)" stroke="#2c6b94" stroke-width="1.5"/>
<text x="60" y="328" fill="#9fe3ff" font-size="15" font-weight="700">3 · manifest-list scan → classify Added entries by data-file content type</text>
<rect x="60" y="350" width="180" height="100" rx="10" fill="url(#chip)" stroke="#3b86b5"/>
<rect x="60" y="350" width="180" height="6" rx="3" fill="url(#ice)"/>
<text x="150" y="380" fill="#dff2ff" font-size="13" text-anchor="middle" font-weight="700">Data</text>
<text x="150" y="404" fill="#bfe6ff" font-size="12" text-anchor="middle">→ added_files</text>
<text x="150" y="424" fill="#86b6d3" font-size="11" text-anchor="middle">rows to INSERT</text>
<rect x="270" y="350" width="190" height="100" rx="10" fill="url(#chip)" stroke="#a9762f"/>
<rect x="270" y="350" width="190" height="6" rx="3" fill="#ffcf7a"/>
<text x="365" y="380" fill="#ffe3b4" font-size="13" text-anchor="middle" font-weight="700">EqualityDeletes</text>
<text x="365" y="404" fill="#ffcf7a" font-size="12" text-anchor="middle">→ delete_files</text>
<text x="365" y="424" fill="#caa269" font-size="11" text-anchor="middle">identity DELETE keys</text>
<rect x="490" y="350" width="170" height="100" rx="10" fill="url(#chip)" stroke="#9a4444"/>
<rect x="490" y="350" width="170" height="6" rx="3" fill="#ff8b8b"/>
<text x="575" y="380" fill="#ffd2d2" font-size="13" text-anchor="middle" font-weight="700">PositionDeletes</text>
<text x="575" y="404" fill="#ff8b8b" font-size="12" text-anchor="middle">→ needs_full_reload</text>
<text x="575" y="424" fill="#c98686" font-size="11" text-anchor="middle">re-read `to` in full</text>
<!-- 4. DeltaPlan -->
<rect x="720" y="110" width="420" height="240" rx="12" fill="url(#chip)" stroke="#7fd4ff" stroke-width="2"/>
<text x="740" y="140" fill="#dff2ff" font-size="17" font-weight="700">DeltaPlan</text>
<text x="740" y="170" fill="#bfe6ff" font-size="13">snapshots: Vec<i64></text>
<text x="740" y="196" fill="#bfe6ff" font-size="13">added_files: Vec<String></text>
<text x="740" y="222" fill="#ffcf7a" font-size="13">delete_files: Vec<EqualityDeleteFile></text>
<text x="740" y="248" fill="#ff8b8b" font-size="13">needs_full_reload: bool</text>
<line x1="740" y1="266" x2="1120" y2="266" stroke="#2c6b94"/>
<text x="740" y="292" fill="#9fe3ff" font-size="12">read_delta → (Vec<RecordBatch>, DeltaPlan)</text>
<text x="740" y="314" fill="#9fe3ff" font-size="12">read_equality_deletes(plan) → deleted identities</text>
<text x="740" y="336" fill="#86b6d3" font-size="12">writer: Table::delete_equality(keys, cols)</text>
<!-- 5. consumers -->
<rect x="720" y="380" width="420" height="100" rx="12" fill="url(#rail)" stroke="#2c6b94" stroke-width="1.5"/>
<text x="740" y="408" fill="#9fe3ff" font-size="14" font-weight="700">consumers (poll commit_seq() → read_delta(cursor, latest))</text>
<text x="740" y="434" fill="#bfe6ff" font-size="12.5">• knut-bifrost — Iceberg → FalkorDB streaming graph ingest</text>
<text x="740" y="458" fill="#bfe6ff" font-size="12.5">• modgunn (Móðguðr) — Engine B world-delta / tripwires (leaf, via skade)</text>
<!-- flow arrows -->
<line x1="340" y1="185" x2="378" y2="185" stroke="#7fd4ff" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="360" y1="300" x2="360" y2="262" stroke="#7fd4ff" stroke-width="0"/>
<line x1="530" y1="300" x2="530" y2="262" stroke="#7fd4ff" stroke-width="2" marker-start="url(#arrow)" marker-end="url(#arrow)"/>
<line x1="240" y1="400" x2="270" y2="400" stroke="#7fd4ff" stroke-width="0"/>
<line x1="680" y1="400" x2="718" y2="300" stroke="#7fd4ff" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="680" y1="185" x2="718" y2="185" stroke="#7fd4ff" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="930" y1="350" x2="930" y2="378" stroke="#7fd4ff" stroke-width="2" marker-end="url(#arrow)"/>
</svg>