.nornir/assets/pipeline_adapter_flow.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="slot" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#123448"/>
<stop offset="1" stop-color="#0a2032"/>
</linearGradient>
<marker id="arrow2" markerWidth="9" markerHeight="9" refX="7" refY="4" orient="auto">
<path d="M0 0 L8 4 L0 8 Z" fill="#6fd3f5"/>
</marker>
</defs>
<rect x="0" y="0" width="1180" height="560" fill="url(#board)"/>
<g stroke="#143a52" stroke-width="1">
<line x1="0" y1="76" x2="1180" y2="76"/>
<line x1="0" y1="512" x2="1180" y2="512"/>
</g>
<g fill="#16415c">
<circle cx="40" cy="40" r="2"/><circle cx="1140" cy="40" r="2"/>
<circle cx="40" cy="532" r="2"/><circle cx="1140" cy="532" r="2"/>
</g>
<!-- title -->
<text x="40" y="44" fill="#eaf6ff" font-size="22" font-weight="700">engine-agnostic pipeline</text>
<text x="370" y="44" fill="#9fc9e0" font-size="15">engine → <tspan fill="#bfe6ff" font-weight="700">PipelineAdapter</tspan> → normalized <tspan fill="#bfe6ff" font-weight="700">PipelineModel</tspan> → PipelineView</text>
<!-- legend -->
<g font-size="12.5">
<line x1="820" y1="60" x2="860" y2="60" stroke="#6fd3f5" stroke-width="3"/>
<text x="868" y="64" fill="#cfe6f5">maps / renders</text>
<line x1="990" y1="60" x2="1030" y2="60" stroke="#7fb0cc" stroke-width="2.5" stroke-dasharray="5 4"/>
<text x="1038" y="64" fill="#cfe6f5">future adapter</text>
</g>
<!-- ===================== ENGINES (left) ===================== -->
<rect x="36" y="120" width="190" height="320" rx="10" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="131" y="146" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">engines</text>
<text x="131" y="165" fill="#9fc9e0" font-size="10.5" text-anchor="middle">each speaks its own types</text>
<rect x="58" y="186" width="146" height="44" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.6"/>
<text x="131" y="204" fill="#bfe6ff" font-size="11" text-anchor="middle" font-weight="700">Spark / SDP</text>
<text x="131" y="220" fill="#7CFFB2" font-size="9" text-anchor="middle">SHIPS NOW · knut</text>
<rect x="58" y="244" width="146" height="36" rx="5" fill="#0a2032" stroke="#3c6a86" stroke-width="1.4" stroke-dasharray="3 3"/>
<text x="131" y="266" fill="#9fc9e0" font-size="11" text-anchor="middle">Flink — future</text>
<rect x="58" y="294" width="146" height="36" rx="5" fill="#0a2032" stroke="#3c6a86" stroke-width="1.4" stroke-dasharray="3 3"/>
<text x="131" y="316" fill="#9fc9e0" font-size="11" text-anchor="middle">Beam — future</text>
<rect x="58" y="344" width="146" height="36" rx="5" fill="#0a2032" stroke="#3c6a86" stroke-width="1.4" stroke-dasharray="3 3"/>
<text x="131" y="366" fill="#9fc9e0" font-size="11" text-anchor="middle">skade-streaming — future</text>
<text x="131" y="406" fill="#7fa8c4" font-size="9.5" text-anchor="middle">a new engine =</text>
<text x="131" y="421" fill="#a9d8ee" font-size="9.5" text-anchor="middle">"just another impl"</text>
<!-- solid (spark), dashed (future) into adapter -->
<path d="M204 208 H300" stroke="#6fd3f5" stroke-width="3" fill="none" marker-end="url(#arrow2)"/>
<g stroke="#7fb0cc" stroke-width="2.5" fill="none" stroke-dasharray="6 4">
<path d="M204 262 H300"/>
<path d="M204 312 H300"/>
<path d="M204 362 H300"/>
</g>
<!-- ===================== PipelineAdapter seam ===================== -->
<rect x="300" y="160" width="200" height="220" rx="12" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2.5"/>
<text x="400" y="186" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">PipelineAdapter</text>
<text x="400" y="205" fill="#9fc9e0" font-size="10.5" text-anchor="middle">the ONE seam (trait)</text>
<rect x="322" y="224" width="156" height="50" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.6"/>
<text x="400" y="244" fill="#bfe6ff" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">to_pipeline_model()</text>
<text x="400" y="261" fill="#9fc9e0" font-size="9" text-anchor="middle">→ PipelineModel</text>
<text x="400" y="298" fill="#86b3cc" font-size="10" text-anchor="middle">knut: SparkPipelineAdapter</text>
<text x="400" y="314" fill="#86b3cc" font-size="10" text-anchor="middle">ViewerState → Stages + Edges</text>
<text x="400" y="336" fill="#a9d8ee" font-size="9.5" text-anchor="middle">no Spark/SDP types leak</text>
<text x="400" y="352" fill="#7fa8c4" font-size="9.5" text-anchor="middle">across the boundary</text>
<path d="M500 270 H556" stroke="#6fd3f5" stroke-width="3" fill="none" marker-end="url(#arrow2)"/>
<!-- ===================== PipelineModel (normalized) ===================== -->
<rect x="556" y="130" width="220" height="300" rx="12" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2.5"/>
<text x="666" y="156" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">PipelineModel</text>
<text x="666" y="175" fill="#9fc9e0" font-size="10.5" text-anchor="middle">normalized · renderer-independent</text>
<rect x="578" y="192" width="176" height="40" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="666" y="209" fill="#bfe6ff" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">Stage</text>
<text x="666" y="224" fill="#9fc9e0" font-size="9" text-anchor="middle">id/name · StageStatus · kind · error · metrics</text>
<rect x="578" y="240" width="176" height="40" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="666" y="257" fill="#bfe6ff" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">PipelineEdge</text>
<text x="666" y="272" fill="#9fc9e0" font-size="9" text-anchor="middle">from → to (by stage id) · label</text>
<rect x="578" y="288" width="176" height="40" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="666" y="305" fill="#bfe6ff" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">PipelineMetrics</text>
<text x="666" y="320" fill="#9fc9e0" font-size="9" text-anchor="middle">fraction · tasks · bytes · (per-stage rows/lag)</text>
<text x="666" y="356" fill="#86b3cc" font-size="10" text-anchor="middle">String ids · neutral StageStatus</text>
<text x="666" y="372" fill="#86b3cc" font-size="10" text-anchor="middle">open metric bags (Option fields)</text>
<text x="666" y="394" fill="#7fa8c4" font-size="9.5" text-anchor="middle">HARD RULE: zero engine semantics</text>
<path d="M776 240 H832" stroke="#6fd3f5" stroke-width="3" fill="none" marker-end="url(#arrow2)"/>
<!-- ===================== PipelineView ===================== -->
<rect x="832" y="170" width="200" height="180" rx="11" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2.5"/>
<text x="932" y="196" fill="#eaf6ff" font-size="14" font-weight="700" text-anchor="middle">PipelineView</text>
<text x="932" y="215" fill="#9fc9e0" font-size="10.5" text-anchor="middle">from_model(&PipelineModel)</text>
<text x="932" y="240" fill="#86b3cc" font-size="10" text-anchor="middle">themed animated DAG</text>
<text x="932" y="256" fill="#86b3cc" font-size="10" text-anchor="middle">+ job-progress bar</text>
<text x="932" y="278" fill="#a9d8ee" font-size="9.5" text-anchor="middle">shared core layered layout</text>
<text x="932" y="296" fill="#7fa8c4" font-size="9.5" text-anchor="middle">legacy new/from_nodes = wrappers</text>
<text x="932" y="320" fill="#86b3cc" font-size="9.5" text-anchor="middle">Falsett persistent geometry</text>
<text x="932" y="335" fill="#86b3cc" font-size="9.5" text-anchor="middle">shared GPU / CPU rendering</text>
<line x1="1032" y1="260" x2="1090" y2="260" stroke="#6fd3f5" stroke-width="3" marker-end="url(#arrow2)"/>
<circle cx="1100" cy="260" r="5" fill="#bfecff"/>
<!-- footer -->
<text x="40" y="540" fill="#5e86a0" font-size="11" font-family="'DejaVu Sans Mono', monospace">facett-pipeline/src/model.rs (model + trait) · knut-pipelines/src/facett_adapter.rs (Spark adapter, feature facett-adapter) · one viewer, many adapters</text>
</svg>