assets/release-pipeline.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 760" 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="1200" height="760" fill="url(#board)"/>
<g stroke="#143a52" stroke-width="1"><line x1="0" y1="76" x2="1200" y2="76"/><line x1="0" y1="712" x2="1200" y2="712"/></g>
<g fill="#16415c"><circle cx="40" cy="40" r="2"/><circle cx="1160" cy="40" r="2"/><circle cx="40" cy="732" r="2"/><circle cx="1160" cy="732" r="2"/></g>
<!-- title -->
<text x="40" y="44" fill="#eaf6ff" font-size="22" font-weight="700">dwarves</text>
<text x="150" y="44" fill="#9fc9e0" font-size="14.5"><tspan font-family="'DejaVu Sans Mono', monospace" fill="#bfe6ff">workspace-release</tspan> — the dry-run machinery: two proofs before a byte reaches <tspan fill="#e0b366" font-weight="700">crates.io</tspan></text>
<!-- legend -->
<g font-size="12">
<line x1="828" y1="60" x2="868" y2="60" stroke="#6fd3f5" stroke-width="3"/>
<text x="876" y="64" fill="#cfe6f5">build / flow</text>
<line x1="988" y1="60" x2="1028" y2="60" stroke="#e0b366" stroke-width="2.5" stroke-dasharray="6 4"/>
<text x="1036" y="64" fill="#cfe6f5">static / gated</text>
</g>
<!-- ===== 1 Discover ===== -->
<rect x="36" y="252" width="120" height="108" rx="10" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="96" y="292" fill="#eaf6ff" font-size="13.5" font-weight="700" text-anchor="middle">1 · Discover</text>
<text x="96" y="312" fill="#9fc9e0" font-size="10" text-anchor="middle">workspace</text>
<text x="96" y="326" fill="#9fc9e0" font-size="10" text-anchor="middle">descriptor</text>
<text x="96" y="344" fill="#86b3cc" font-size="9.5" text-anchor="middle">members + held</text>
<rect x="156" y="302" width="6" height="8" fill="#6fd3f5"/>
<!-- ===== 2 Deps-first order ===== -->
<rect x="176" y="230" width="152" height="152" rx="11" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2.2"/>
<text x="252" y="256" fill="#eaf6ff" font-size="13.5" font-weight="700" text-anchor="middle">2 · Deps-first order</text>
<rect x="196" y="272" width="112" height="30" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.5"/>
<text x="252" y="285" fill="#bfe6ff" font-size="9.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">Tarjan SCC</text>
<text x="252" y="297" fill="#9fc9e0" font-size="8.5" text-anchor="middle">condense cycles → DAG</text>
<rect x="196" y="310" width="112" height="30" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.5"/>
<text x="252" y="323" fill="#bfe6ff" font-size="9.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">Kahn topo</text>
<text x="252" y="335" fill="#9fc9e0" font-size="8.5" text-anchor="middle">crate-level interleave</text>
<text x="252" y="360" fill="#86b3cc" font-size="9" text-anchor="middle">deps publish first</text>
<rect x="328" y="302" width="6" height="8" fill="#6fd3f5"/>
<!-- ===== 3 Verify ===== -->
<rect x="348" y="252" width="128" height="108" rx="10" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="412" y="292" fill="#eaf6ff" font-size="13.5" font-weight="700" text-anchor="middle">3 · Verify</text>
<text x="412" y="312" fill="#9fc9e0" font-size="10" text-anchor="middle">cargo test</text>
<text x="412" y="326" fill="#9fc9e0" font-size="10" text-anchor="middle">+ offline gates</text>
<text x="412" y="344" fill="#86b3cc" font-size="9" text-anchor="middle">--skip-tests to skip</text>
<rect x="476" y="302" width="6" height="8" fill="#6fd3f5"/>
<!-- flow 1->2->3->A -->
<g stroke="#6fd3f5" stroke-width="3" fill="none">
<path d="M162 306 H176"/><path d="M334 306 H348"/><path d="M482 306 H498"/>
</g>
<g fill="#bfecff"><circle cx="176" cy="306" r="3"/><circle cx="348" cy="306" r="3"/><circle cx="498" cy="306" r="3"/></g>
<!-- ===== Gate A (static) ===== -->
<rect x="498" y="140" width="196" height="360" rx="12" fill="url(#rail)" stroke="#e0b366" stroke-width="2.4" stroke-dasharray="2 0"/>
<text x="596" y="168" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">Gate A</text>
<text x="596" y="187" fill="#f0cf94" font-size="10.5" text-anchor="middle">static precheck</text>
<text x="596" y="203" fill="#c69a54" font-size="9.5" text-anchor="middle">milliseconds · NO build</text>
<rect x="518" y="220" width="156" height="42" rx="6" fill="url(#slot)" stroke="#e0b366" stroke-width="1.4"/>
<text x="596" y="238" fill="#f4e2bf" font-size="10.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">G_io ⊕ G_src</text>
<text x="596" y="253" fill="#c8b183" font-size="8.5" text-anchor="middle">crates.io reality + local</text>
<rect x="518" y="270" width="156" height="42" rx="6" fill="url(#slot)" stroke="#e0b366" stroke-width="1.4"/>
<text x="596" y="288" fill="#f4e2bf" font-size="10.5" text-anchor="middle">resolvable?</text>
<text x="596" y="303" fill="#c8b183" font-size="8.5" text-anchor="middle">PubGrub + explanation</text>
<rect x="518" y="320" width="156" height="46" rx="6" fill="url(#slot)" stroke="#e0b366" stroke-width="1.6"/>
<text x="596" y="338" fill="#f4e2bf" font-size="10.5" text-anchor="middle">feature-soundness</text>
<text x="596" y="353" fill="#c8b183" font-size="9" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">Φ ⊆ exposed</text>
<text x="596" y="392" fill="#86b3cc" font-size="9" text-anchor="middle">no publish=false dep</text>
<text x="596" y="407" fill="#86b3cc" font-size="9" text-anchor="middle">no bare * · path-dep has version</text>
<text x="596" y="422" fill="#86b3cc" font-size="9" text-anchor="middle">acyclic-after-condensation</text>
<text x="596" y="452" fill="#f0cf94" font-size="9.5" text-anchor="middle">proves it CAN resolve</text>
<rect x="694" y="306" width="6" height="8" fill="#6fd3f5"/>
<!-- flow A -> B -->
<g stroke="#6fd3f5" stroke-width="3" fill="none"><path d="M700 310 H716"/></g>
<circle cx="716" cy="310" r="3" fill="#bfecff"/>
<!-- ===== Gate B (constructive) ===== -->
<rect x="716" y="140" width="316" height="520" rx="12" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2.6"/>
<text x="874" y="168" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">Gate B</text>
<text x="874" y="187" fill="#9fc9e0" font-size="10.5" text-anchor="middle">constructive rehearsal</text>
<text x="874" y="203" fill="#7fbfe0" font-size="9.5" text-anchor="middle">BUILDS · nothing to crates.io</text>
<!-- served holger /sparring -->
<rect x="734" y="216" width="280" height="132" rx="10" fill="url(#chip)" stroke="#5aa6cf" stroke-width="1.8"/>
<text x="874" y="238" fill="#eaf6ff" font-size="12" font-weight="700" text-anchor="middle">served holger <tspan font-family="'DejaVu Sans Mono', monospace" fill="#bfe6ff">/sparring</tspan></text>
<text x="874" y="252" fill="#86b3cc" font-size="9" text-anchor="middle">127.0.0.1 · throwaway · loopback only</text>
<rect x="748" y="262" width="122" height="40" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="809" y="279" fill="#bfe6ff" font-size="9.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">/cache</text>
<text x="809" y="293" fill="#9fc9e0" font-size="8.5" text-anchor="middle">crates.io mirror</text>
<rect x="878" y="262" width="122" height="40" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="939" y="279" fill="#bfe6ff" font-size="9.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">/sparring</text>
<text x="939" y="293" fill="#9fc9e0" font-size="8.5" text-anchor="middle">writable · cascade lands</text>
<text x="874" y="322" fill="#86b3cc" font-size="9" text-anchor="middle">crates.io source-replaced onto the mirror —</text>
<text x="874" y="336" fill="#86b3cc" font-size="9" text-anchor="middle">17 repos resolve EACH OTHER as if published</text>
<!-- cascade -->
<text x="734" y="374" fill="#9fc9e0" font-size="10.5" font-weight="700">for each crate, deps-first:</text>
<rect x="734" y="382" width="280" height="30" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="746" y="401" fill="#cfe6f5" font-size="9.5">① reconcile Cargo.lock → /sparring versions</text>
<rect x="734" y="418" width="280" height="30" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.6"/>
<text x="746" y="437" fill="#bfe6ff" font-size="9" font-family="'DejaVu Sans Mono', monospace">② cargo publish -p X --registry sparring</text>
<rect x="734" y="454" width="280" height="30" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="746" y="473" fill="#cfe6f5" font-size="9.5">③ wait-for-index — until /sparring serves X</text>
<rect x="734" y="490" width="280" height="30" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="746" y="509" fill="#cfe6f5" font-size="9.5">④ record shipped version → next consumer</text>
<text x="874" y="540" fill="#86b3cc" font-size="9" text-anchor="middle">② is a real VERIFY BUILD — the point of the gate</text>
<text x="874" y="556" fill="#86b3cc" font-size="9" text-anchor="middle">lock-neutral: every consumer lock restored, no trace</text>
<text x="874" y="572" fill="#f0a9a9" font-size="9" text-anchor="middle">any crate fails ⇒ REFUSE, dump cargo error, upload nothing</text>
<text x="874" y="600" fill="#7fbfe0" font-size="9.5" text-anchor="middle">proves it DOES build + publish</text>
<rect x="1032" y="306" width="6" height="8" fill="#6fd3f5"/>
<!-- flow B -> Decision -->
<g stroke="#6fd3f5" stroke-width="3" fill="none"><path d="M1038 310 H1052"/></g>
<circle cx="1052" cy="310" r="3" fill="#bfecff"/>
<!-- ===== Decision ===== -->
<rect x="1052" y="240" width="124" height="140" rx="10" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2"/>
<text x="1114" y="266" fill="#eaf6ff" font-size="12.5" font-weight="700" text-anchor="middle">Decision</text>
<text x="1114" y="282" fill="#9fc9e0" font-size="9" text-anchor="middle">both gates green?</text>
<rect x="1064" y="292" width="100" height="34" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="1114" y="308" fill="#bfe6ff" font-size="9" text-anchor="middle">dry-run</text>
<text x="1114" y="320" fill="#9fc9e0" font-size="8" text-anchor="middle">print PLAN · upload 0</text>
<rect x="1064" y="332" width="100" height="34" rx="6" fill="url(#slot)" stroke="#e0b366" stroke-width="1.6"/>
<text x="1114" y="348" fill="#f4e2bf" font-size="9" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">--execute</text>
<text x="1114" y="360" fill="#c8b183" font-size="8" text-anchor="middle">publish deps-first</text>
<!-- Decision -> crates.io (gated, dashed amber) -->
<g stroke="#e0b366" stroke-width="2.5" fill="none" stroke-dasharray="6 4"><path d="M1114 380 V430"/></g>
<circle cx="1114" cy="430" r="3" fill="#f0cf94"/>
<!-- ===== crates.io (guarded target) ===== -->
<rect x="1046" y="430" width="136" height="88" rx="11" fill="#241a0c" stroke="#e0b366" stroke-width="2.4"/>
<text x="1114" y="458" fill="#f4e2bf" font-size="13" font-weight="700" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">crates.io</text>
<text x="1114" y="478" fill="#c8b183" font-size="9" text-anchor="middle">only on --execute</text>
<text x="1114" y="493" fill="#a88b57" font-size="8.5" text-anchor="middle">append-only</text>
<text x="1114" y="508" fill="#a88b57" font-size="8.5" text-anchor="middle">after BOTH gates green</text>
<!-- ===== ground rail (properties) ===== -->
<rect x="36" y="632" width="656" height="60" rx="10" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2"/>
<g fill="#0a1c2c" stroke="#7fc8ea" stroke-width="1.5"><circle cx="80" cy="662" r="4"/><circle cx="360" cy="662" r="4"/><circle cx="640" cy="662" r="4"/></g>
<text x="98" y="661" fill="#dff1ff" font-size="14" font-weight="700">properties</text>
<text x="200" y="656" fill="#bcd9ec" font-size="10.5">two proofs before crates.io · Gate A static (ms) · Gate B builds a throwaway registry</text>
<text x="200" y="676" fill="#7fa8c4" font-size="9.5" font-family="'DejaVu Sans Mono', monospace">deps-first · lock-neutral · feature-aware · nothing uploaded until both gates green</text>
</svg>