Gunnar

mikronova/draupnir

.nornir/assets/flow_run_to_completion.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>
    <marker id="arr" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto"><path d="M0 0 L7 3 L0 6 Z" fill="#6fd3f5"/></marker>
    <marker id="arrd" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto"><path d="M0 0 L7 3 L0 6 Z" fill="#7fb0cc"/></marker>
  </defs>

  <rect x="0" y="0" width="1180" height="560" fill="url(#board)"/>
  <g stroke="#143a52" stroke-width="1"><line x1="0" y1="74" x2="1180" y2="74"/><line x1="0" y1="520" x2="1180" y2="520"/></g>
  <g fill="#16415c"><circle cx="40" cy="40" r="2"/><circle cx="1140" cy="40" r="2"/><circle cx="40" cy="540" r="2"/><circle cx="1140" cy="540" r="2"/></g>

  <text x="40" y="44" fill="#eaf6ff" font-size="22" font-weight="700">run_to_completion — one engine, one run-to-completion seam</text>
  <text x="40" y="66" fill="#9fc9e0" font-size="13.5">nornir job &#8594; jera policy &#8594; draupnir orchestrates the ONE bollard engine &#8594; {exit_code, stdout, stderr}</text>

  <!-- nornir job -->
  <rect x="40" y="150" width="200" height="92" rx="10" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
  <text x="140" y="182" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">nornir::jobs</text>
  <text x="140" y="202" fill="#9fc9e0" font-size="11" text-anchor="middle">run_container</text>
  <text x="140" y="222" fill="#86b3cc" font-size="10" text-anchor="middle">the app-level job call</text>

  <!-- jera policy -->
  <rect x="296" y="150" width="200" height="92" rx="10" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
  <text x="396" y="182" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">jera::container</text>
  <text x="396" y="202" fill="#9fc9e0" font-size="11" text-anchor="middle">run_container &#8594; ledger row</text>
  <text x="396" y="222" fill="#86b3cc" font-size="10" text-anchor="middle">job policy only &#8226; no engine</text>

  <!-- draupnir seam -->
  <rect x="552" y="138" width="216" height="116" rx="10" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2.5"/>
  <text x="660" y="168" fill="#eaf6ff" font-size="15" font-weight="700" text-anchor="middle">draupnir::container</text>
  <text x="660" y="190" fill="#9fc9e0" font-size="11.5" text-anchor="middle">run_to_completion(spec)</text>
  <text x="660" y="210" fill="#86b3cc" font-size="10" text-anchor="middle">generic over Boot + ContainerControl</text>
  <text x="660" y="228" fill="#86b3cc" font-size="10" text-anchor="middle">boot &#8594; poll state &#8594; drain logs &#8594; stop</text>
  <text x="660" y="245" fill="#86b3cc" font-size="10" text-anchor="middle">(mock-testable: no daemon)</text>

  <!-- ContainerBoot -->
  <rect x="824" y="150" width="200" height="92" rx="10" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
  <text x="924" y="182" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">ContainerBoot</text>
  <text x="924" y="202" fill="#9fc9e0" font-size="11" text-anchor="middle">Engine (bollard)</text>
  <text x="924" y="220" fill="#86b3cc" font-size="10" text-anchor="middle">the ONE OCI engine</text>

  <!-- daemon rail -->
  <rect x="824" y="322" width="200" height="52" rx="10" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2"/>
  <text x="924" y="346" fill="#dff1ff" font-size="13.5" font-weight="700" text-anchor="middle">podman / Docker socket</text>
  <text x="924" y="364" fill="#7fa8c4" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">zero-shell REST &#8226; no CLI</text>

  <!-- outcome rail -->
  <rect x="296" y="322" width="472" height="52" rx="10" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2"/>
  <text x="322" y="347" fill="#dff1ff" font-size="14" font-weight="700">RunOutcome</text>
  <text x="420" y="346" fill="#bcd9ec" font-size="12">{ exit_code: Option&lt;i64&gt;, stdout: Vec&lt;String&gt;, stderr: Vec&lt;String&gt; }</text>
  <text x="420" y="364" fill="#7fa8c4" font-size="10" font-family="'DejaVu Sans Mono', monospace">non-zero exit is Ok(outcome), not Err &#8226; mirrors jera's ContainerOutcome</text>

  <!-- forward arrows -->
  <g stroke="#6fd3f5" stroke-width="3" fill="none">
    <path d="M240 196 H294" marker-end="url(#arr)"/>
    <path d="M496 196 H550 V196 H550" marker-end="url(#arr)"/>
    <path d="M768 196 H822" marker-end="url(#arr)"/>
    <path d="M924 242 V320" marker-end="url(#arr)"/>
  </g>
  <!-- outcome return (dashed) -->
  <path d="M824 348 H770" stroke="#7fb0cc" stroke-width="2.5" fill="none" stroke-dasharray="6 4" marker-end="url(#arrd)"/>
  <path d="M296 348 H150 V244" stroke="#7fb0cc" stroke-width="2.5" fill="none" stroke-dasharray="6 4" marker-end="url(#arrd)"/>

  <text x="40" y="470" fill="#9fc9e0" font-size="12" font-weight="700">Consolidation:</text>
  <text x="140" y="470" fill="#86b3cc" font-size="11.5">once nornir repoints its run_container onto this seam, jera's duplicate BollardEngine becomes dead code and is deleted &#8212; one engine, not two.</text>
  <text x="40" y="496" fill="#9fc9e0" font-size="12" font-weight="700">Mirror:</text>
  <text x="140" y="496" fill="#86b3cc" font-size="11.5">exactly how a VM/container *boot* already delegates through draupnir::Boot &#8212; this is the run-to-completion analogue.</text>
</svg>