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

nordisk/knut

.nornir/assets/bifrost_flow.svg

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1180 680" 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="slot" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#123448"/>
      <stop offset="1" stop-color="#0a2032"/>
    </linearGradient>
    <linearGradient id="bifrost" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0" stop-color="#6fd3f5" stop-opacity="0.9"/>
      <stop offset="0.5" stop-color="#a98fe0" stop-opacity="0.8"/>
      <stop offset="1" stop-color="#f59ec0" stop-opacity="0.8"/>
    </linearGradient>
  </defs>

  <!-- PCB substrate -->
  <rect x="0" y="0" width="1180" height="680" fill="url(#board)"/>
  <g stroke="#143a52" stroke-width="1">
    <line x1="0" y1="76" x2="1180" y2="76"/>
    <line x1="0" y1="632" x2="1180" y2="632"/>
  </g>
  <g fill="#16415c">
    <circle cx="40" cy="40" r="2"/><circle cx="1140" cy="40" r="2"/>
    <circle cx="40" cy="652" r="2"/><circle cx="1140" cy="652" r="2"/>
  </g>

  <!-- title -->
  <text x="40" y="44" fill="#eaf6ff" font-size="22" font-weight="700">Bifr&#246;st &#127752;</text>
  <text x="200" y="44" fill="#9fc9e0" font-size="15">tables &#8594; graph &#8594; query &#8212; the bridge that materialises lakehouse rows as a <tspan fill="#bfe6ff" font-weight="700">live property graph</tspan></text>

  <!-- legend -->
  <g font-size="12.5">
    <line x1="804" y1="60" x2="844" y2="60" stroke="#6fd3f5" stroke-width="3"/>
    <text x="852" y="64" fill="#cfe6f5">sync / query path</text>
    <line x1="1006" y1="60" x2="1046" y2="60" stroke="#7fb0cc" stroke-width="2.5" stroke-dasharray="5 4"/>
    <text x="1054" y="64" fill="#cfe6f5">state-after-sink</text>
  </g>

  <!-- ===================== SOURCES (left) ===================== -->
  <rect x="36" y="118" width="180" height="240" rx="11" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
  <text x="126" y="146" fill="#eaf6ff" font-size="14" font-weight="700" text-anchor="middle">TableSource</text>
  <text x="126" y="164" fill="#9fc9e0" font-size="10" text-anchor="middle">watch + poll</text>
  <g font-family="'DejaVu Sans Mono', monospace" font-size="9.5">
    <rect x="56" y="178" width="140" height="36" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
    <text x="66" y="192" fill="#bfe6ff">SparkConnectSource</text>
    <text x="66" y="206" fill="#86b3cc" font-size="8.5">Iceberg via sc:// (spark)</text>
    <rect x="56" y="220" width="140" height="36" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
    <text x="66" y="234" fill="#bfe6ff">IcebergSource</text>
    <text x="66" y="248" fill="#86b3cc" font-size="8.5">Spark-free &#183; full or delta scan</text>
    <rect x="56" y="262" width="140" height="36" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
    <text x="66" y="276" fill="#bfe6ff">FileSource</text>
    <text x="66" y="290" fill="#86b3cc" font-size="8.5">directory of file drops</text>
  </g>
  <text x="126" y="318" fill="#86b3cc" font-size="9" text-anchor="middle">REFRESH TABLE before each poll</text>
  <text x="126" y="332" fill="#a9d8ee" font-size="9" text-anchor="middle">SyncMode: Full / Incremental / Cdc</text>
  <text x="126" y="348" fill="#7fa8c4" font-size="8.5" text-anchor="middle">zero-copy Arrow 58 bridge (skade)</text>
  <rect x="216" y="234" width="6" height="8" fill="#6fd3f5"/>

  <g stroke="#6fd3f5" stroke-width="3" fill="none"><path d="M216 238 H266"/></g>
  <circle cx="266" cy="238" r="4" fill="#bfecff"/>

  <!-- ===================== TRANSFORM FABRIC ===================== -->
  <rect x="266" y="140" width="190" height="200" rx="11" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2"/>
  <text x="361" y="168" fill="#eaf6ff" font-size="13.5" font-weight="700" text-anchor="middle">transform fabric</text>
  <text x="361" y="186" fill="#9fc9e0" font-size="9.5" text-anchor="middle">RecordBatch &#8594; GraphMutation</text>
  <g font-family="'DejaVu Sans Mono', monospace" font-size="9.5">
    <rect x="286" y="198" width="150" height="24" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.2"/>
    <text x="296" y="214" fill="#bfe6ff">MappingSpec (YAML)</text>
    <rect x="286" y="226" width="150" height="24" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.2"/>
    <text x="296" y="242" fill="#bfe6ff">vertex / edge / fk_edges</text>
    <rect x="286" y="254" width="150" height="24" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.2"/>
    <text x="296" y="270" fill="#bfe6ff">WasmTransform (wasmi)</text>
    <rect x="286" y="282" width="150" height="24" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.2"/>
    <text x="296" y="298" fill="#bfe6ff">FlightTransform (DoExchange)</text>
  </g>
  <text x="361" y="324" fill="#7fa8c4" font-size="8.5" text-anchor="middle">CDC: INSERT&#8594;upsert &#183; DELETE last</text>
  <rect x="450" y="234" width="6" height="8" fill="#6fd3f5"/>

  <g stroke="#6fd3f5" stroke-width="3" fill="none"><path d="M456 238 H506"/></g>
  <circle cx="506" cy="238" r="4" fill="#bfecff"/>

  <!-- ===================== SINK -> FALKORDB ===================== -->
  <rect x="506" y="160" width="170" height="160" rx="11" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2.5"/>
  <text x="591" y="188" fill="#eaf6ff" font-size="13.5" font-weight="700" text-anchor="middle">FalkorDbSink</text>
  <text x="591" y="207" fill="#bfe6ff" font-size="10" text-anchor="middle" font-weight="700">idempotent MERGE</text>
  <text x="591" y="227" fill="#9fc9e0" font-size="9.5" text-anchor="middle">UNWIND &#8230; MERGE (Cypher)</text>
  <text x="591" y="245" fill="#86b3cc" font-size="9" text-anchor="middle">MERGE both endpoints / edge</text>
  <text x="591" y="259" fill="#86b3cc" font-size="9" text-anchor="middle">vertices &#8594; edges &#8594; deletes</text>
  <text x="591" y="278" fill="#a9d8ee" font-size="9" text-anchor="middle">FalkorDB (Redis/Valkey module)</text>
  <text x="591" y="294" fill="#7fa8c4" font-size="8.5" text-anchor="middle">nodes carry _gar_id</text>
  <text x="591" y="310" fill="#7fa8c4" font-size="8.5" text-anchor="middle">DETACH DELETE clears incident edges</text>
  <rect x="500" y="234" width="6" height="8" fill="#6fd3f5"/>
  <rect x="676" y="234" width="6" height="8" fill="#6fd3f5"/>

  <!-- state-after-sink dashed back to source -->
  <path d="M591 320 V360 H361 V340" stroke="#7fb0cc" stroke-width="2.5" fill="none" stroke-dasharray="6 4"/>
  <text x="470" y="354" fill="#86b3cc" font-size="9" text-anchor="middle">state written only AFTER sink &#8594; crash replays (MERGE idempotent)</text>

  <g stroke="#6fd3f5" stroke-width="3" fill="none"><path d="M676 238 H726"/></g>
  <circle cx="726" cy="238" r="4" fill="#bfecff"/>

  <!-- ===================== FLIGHT SQL (query out) ===================== -->
  <rect x="726" y="160" width="180" height="160" rx="11" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2"/>
  <text x="816" y="188" fill="#eaf6ff" font-size="13.5" font-weight="700" text-anchor="middle">graphar-flight</text>
  <text x="816" y="206" fill="#9fc9e0" font-size="9.5" text-anchor="middle">Arrow Flight SQL server</text>
  <text x="816" y="226" fill="#bfe6ff" font-size="9.5" text-anchor="middle" font-weight="700">Cypher in &#8594; Arrow out</text>
  <text x="816" y="244" fill="#86b3cc" font-size="9" text-anchor="middle">GRAPH.QUERY &#8594; RecordBatch stream</text>
  <text x="816" y="262" fill="#86b3cc" font-size="9" text-anchor="middle">auth: bearer / Basic / mTLS</text>
  <text x="816" y="282" fill="#a9d8ee" font-size="9" text-anchor="middle">graph &#8594; lakehouse export</text>
  <text x="816" y="298" fill="#7fa8c4" font-size="8.5" text-anchor="middle">GraphAr file or Iceberg table</text>
  <rect x="720" y="234" width="6" height="8" fill="#6fd3f5"/>
  <rect x="906" y="234" width="6" height="8" fill="#6fd3f5"/>

  <g stroke="#6fd3f5" stroke-width="3" fill="none"><path d="M906 238 H956"/></g>
  <circle cx="956" cy="238" r="4" fill="#bfecff"/>

  <!-- ===================== KNUT PY CLIENT ===================== -->
  <rect x="956" y="178" width="184" height="124" rx="11" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2.5"/>
  <text x="1048" y="206" fill="#eaf6ff" font-size="14" font-weight="700" text-anchor="middle">knut (Python)</text>
  <text x="1048" y="224" fill="#9fc9e0" font-size="9.5" text-anchor="middle">KnutClient &#183; DoGet / DoPut</text>
  <text x="1048" y="244" fill="#bfe6ff" font-size="9.5" text-anchor="middle" font-weight="700">pandas &#8594; NetworkX</text>
  <text x="1048" y="262" fill="#86b3cc" font-size="9" text-anchor="middle">nx.from_pandas_edgelist</text>
  <text x="1048" y="276" fill="#86b3cc" font-size="9" text-anchor="middle">nx.set_node_attributes</text>
  <text x="1048" y="294" fill="#7fa8c4" font-size="8.5" text-anchor="middle">analyse / visualise the graph</text>
  <rect x="950" y="234" width="6" height="8" fill="#6fd3f5"/>

  <!-- after-round emit (down to the rail) -->
  <g stroke="#6fd3f5" stroke-width="3" fill="none">
    <path d="M591 320 V440 H440 V552"/>
    <path d="M1048 302 V470 H720 V552"/>
  </g>
  <g fill="#bfecff"><circle cx="440" cy="552" r="4"/><circle cx="720" cy="552" r="4"/></g>
  <text x="540" y="436" fill="#86b3cc" font-size="9" text-anchor="middle">after each round &#8594; emit + metrics</text>

  <!-- ===================== GROUND RAIL: DAG citizen ===================== -->
  <rect x="36" y="552" width="1104" height="56" rx="10" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2"/>
  <g fill="#0a1c2c" stroke="#7fc8ea" stroke-width="1.5">
    <circle cx="80" cy="580" r="4"/><circle cx="420" cy="580" r="4"/>
    <circle cx="720" cy="580" r="4"/><circle cx="1040" cy="580" r="4"/>
  </g>
  <text x="106" y="579" fill="#dff1ff" font-size="14" font-weight="700">round &#8594; emit</text>
  <text x="240" y="575" fill="#bcd9ec" font-size="11">each successful round &#8594; Airflow 3 AIP-82 asset event &#183; /metrics (Prometheus) after each round</text>
  <text x="240" y="596" fill="#7fa8c4" font-size="10" font-family="'DejaVu Sans Mono', monospace">ledger: File or Valkey backend &#183; backoff on no-progress (idle &#8800; failure) &#183; exactly-once-ish</text>
</svg>