.nornir/assets/viz_thin_rpc.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>
</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">viz · thin RPC</text>
<text x="252" y="44" fill="#9fc9e0" font-size="15">no config → thin client out of the box: a tab → a gRPC call → a <tspan fill="#bfe6ff" font-weight="700">table</tspan></text>
<!-- legend -->
<g font-size="12.5">
<line x1="744" y1="60" x2="784" y2="60" stroke="#6fd3f5" stroke-width="3"/>
<text x="792" y="64" fill="#cfe6f5">thin gRPC (remote)</text>
<line x1="976" y1="60" x2="1016" y2="60" stroke="#7fb0cc" stroke-width="2.5" stroke-dasharray="5 4"/>
<text x="1024" y="64" fill="#cfe6f5">fat (local)</text>
</g>
<!-- ===================== RESOLUTION (left) ===================== -->
<rect x="36" y="118" width="200" height="260" rx="11" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="136" y="146" fill="#eaf6ff" font-size="14" font-weight="700" text-anchor="middle">run_viz resolves</text>
<g font-family="'DejaVu Sans Mono', monospace" font-size="9.5">
<rect x="56" y="160" width="160" height="32" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
<text x="66" y="174" fill="#bfe6ff">1 NORNIR_SERVER set</text>
<text x="66" y="187" fill="#86b3cc" font-size="8.5">→ THIN (explicit)</text>
<rect x="56" y="198" width="160" height="32" rx="6" fill="url(#slot)" stroke="#7fb0cc" stroke-width="1.3"/>
<text x="66" y="212" fill="#cfe6f5">2 --warehouse <dir></text>
<text x="66" y="225" fill="#86b3cc" font-size="8.5">→ FAT/embedded</text>
<rect x="56" y="236" width="160" height="32" rx="6" fill="url(#slot)" stroke="#7fb0cc" stroke-width="1.3"/>
<text x="66" y="250" fill="#cfe6f5">3 config found?</text>
<text x="66" y="263" fill="#86b3cc" font-size="8.5">workspace_<n> → FAT</text>
<rect x="56" y="274" width="160" height="40" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
<text x="66" y="288" fill="#bfe6ff">4 no config</text>
<text x="66" y="300" fill="#86b3cc" font-size="8.5">→ THIN: probe :7878</text>
<text x="66" y="310" fill="#86b3cc" font-size="8.5">token ← ~/.nornir/token</text>
</g>
<text x="136" y="340" fill="#bfe6ff" font-size="10" text-anchor="middle" font-weight="700">no config ⇒ thin</text>
<text x="136" y="356" fill="#7fa8c4" font-size="9" text-anchor="middle">show the server's catalog</text>
<text x="136" y="370" fill="#7fa8c4" font-size="9" text-anchor="middle">no env-var, no flags</text>
<rect x="236" y="240" width="6" height="8" fill="#6fd3f5"/>
<g stroke="#6fd3f5" stroke-width="3" fill="none"><path d="M236 244 H300"/></g>
<circle cx="300" cy="244" r="4" fill="#bfecff"/>
<!-- ===================== VIZ APP / TABS ===================== -->
<rect x="300" y="118" width="190" height="300" rx="12" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2"/>
<text x="395" y="146" fill="#eaf6ff" font-size="14" font-weight="700" text-anchor="middle">urdr-threads</text>
<text x="395" y="164" fill="#9fc9e0" font-size="10" text-anchor="middle">workspace picker (top bar)</text>
<g font-family="'DejaVu Sans Mono', monospace" font-size="10">
<rect x="320" y="178" width="150" height="24" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
<text x="332" y="194" fill="#bfe6ff">Timeline</text>
<rect x="320" y="208" width="150" height="24" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
<text x="332" y="224" fill="#bfe6ff">Release Ops</text>
<rect x="320" y="238" width="150" height="24" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
<text x="332" y="254" fill="#bfe6ff">Test · Funnel</text>
<rect x="320" y="268" width="150" height="24" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
<text x="332" y="284" fill="#bfe6ff">Warehouse Tables</text>
</g>
<text x="395" y="316" fill="#86b3cc" font-size="9.5" text-anchor="middle">each tab issues a verb</text>
<text x="395" y="334" fill="#a9d8ee" font-size="9.5" text-anchor="middle">live toggle auto-refresh ~5s</text>
<text x="395" y="352" fill="#86b3cc" font-size="9" text-anchor="middle">sends nornir-workspace: <name></text>
<text x="395" y="366" fill="#7fa8c4" font-size="9" text-anchor="middle">switch picker → re-scope every tab live</text>
<rect x="490" y="218" width="6" height="8" fill="#6fd3f5"/>
<!-- thin path out -->
<g stroke="#6fd3f5" stroke-width="3" fill="none"><path d="M490 222 H560"/></g>
<circle cx="560" cy="222" r="4" fill="#bfecff"/>
<!-- fat path down (dashed) -->
<path d="M395 418 V470 H940" stroke="#7fb0cc" stroke-width="2.5" fill="none" stroke-dasharray="6 4"/>
<text x="650" y="464" fill="#86b3cc" font-size="10" text-anchor="middle">fat: open_read_only() the local ~/.nornir warehouse directly — no RPC</text>
<!-- ===================== gRPC SERVICES ===================== -->
<rect x="560" y="150" width="180" height="200" rx="11" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2.5"/>
<text x="650" y="178" fill="#eaf6ff" font-size="13.5" font-weight="700" text-anchor="middle">gRPC services</text>
<text x="650" y="196" fill="#9fc9e0" font-size="9.5" text-anchor="middle">bearer token on every call</text>
<g font-family="'DejaVu Sans Mono', monospace" font-size="9.5">
<rect x="578" y="208" width="144" height="22" rx="4" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.2"/>
<text x="588" y="223" fill="#bfe6ff">Viz.Timeline</text>
<rect x="578" y="234" width="144" height="22" rx="4" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.2"/>
<text x="588" y="249" fill="#bfe6ff">Warehouse.Tables</text>
<rect x="578" y="260" width="144" height="22" rx="4" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.2"/>
<text x="588" y="275" fill="#bfe6ff">Warehouse.Scan</text>
<rect x="578" y="286" width="144" height="22" rx="4" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.2"/>
<text x="588" y="301" fill="#bfe6ff">Workspaces.List</text>
</g>
<text x="650" y="330" fill="#7fa8c4" font-size="9" text-anchor="middle">token: --token · $NORNIR_SERVER_TOKEN</text>
<text x="650" y="343" fill="#7fa8c4" font-size="9" text-anchor="middle">· ~/.nornir/token (600)</text>
<rect x="554" y="222" width="6" height="8" fill="#6fd3f5"/>
<rect x="740" y="222" width="6" height="8" fill="#6fd3f5"/>
<g stroke="#6fd3f5" stroke-width="3" fill="none"><path d="M740 226 H810"/></g>
<circle cx="810" cy="226" r="4" fill="#bfecff"/>
<!-- ===================== SERVER ===================== -->
<rect x="810" y="150" width="170" height="200" rx="11" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2"/>
<text x="895" y="178" fill="#eaf6ff" font-size="14" font-weight="700" text-anchor="middle">nornir-server</text>
<text x="895" y="196" fill="#bfe6ff" font-size="10" text-anchor="middle" font-weight="700">sole warehouse writer</text>
<text x="895" y="218" fill="#9fc9e0" font-size="9.5" text-anchor="middle">serves each monitored</text>
<text x="895" y="232" fill="#9fc9e0" font-size="9.5" text-anchor="middle">workspace's builds/ warehouse</text>
<text x="895" y="254" fill="#86b3cc" font-size="9" text-anchor="middle">republishes THROUGH the</text>
<text x="895" y="268" fill="#86b3cc" font-size="9" text-anchor="middle">served handle → live reads</text>
<text x="895" y="292" fill="#a9d8ee" font-size="9" text-anchor="middle">picker = Workspaces.List</text>
<text x="895" y="308" fill="#7fa8c4" font-size="9" text-anchor="middle">all the server's workspaces</text>
<rect x="804" y="222" width="6" height="8" fill="#6fd3f5"/>
<rect x="980" y="222" width="6" height="8" fill="#6fd3f5"/>
<g stroke="#6fd3f5" stroke-width="3" fill="none"><path d="M980 226 H1040 V560"/></g>
<!-- result back up arrow into tabs (dashed return) -->
<path d="M650 350 V400 H395 V418" stroke="#7fb0cc" stroke-width="2" fill="none" stroke-dasharray="4 3"/>
<text x="520" y="396" fill="#86b3cc" font-size="9" text-anchor="middle">Arrow batch → table render</text>
<!-- ===================== WAREHOUSE GROUND RAIL ===================== -->
<rect x="300" y="552" width="840" height="56" rx="10" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2"/>
<g fill="#0a1c2c" stroke="#7fc8ea" stroke-width="1.5">
<circle cx="344" cy="580" r="4"/><circle cx="640" cy="580" r="4"/>
<circle cx="900" cy="580" r="4"/><circle cx="1100" cy="580" r="4"/>
</g>
<text x="370" y="579" fill="#dff1ff" font-size="14" font-weight="700">warehouse</text>
<text x="490" y="575" fill="#bcd9ec" font-size="11">one redb catalog + Iceberg tables · thin reads it via RPC, fat reads it on disk</text>
<text x="490" y="596" fill="#7fa8c4" font-size="10" font-family="'DejaVu Sans Mono', monospace">~/.nornir/workspaces/<name>/builds/warehouse · CLI parity: every tab maps to a verb</text>
</svg>