<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Controlmaster on Nick Liu - Software Engineer</title><link>https://nick-liu.com/tags/controlmaster/</link><description>Recent content in Controlmaster on Nick Liu - Software Engineer</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>nickboy@users.noreply.github.com (Nick Liu)</managingEditor><webMaster>nickboy@users.noreply.github.com (Nick Liu)</webMaster><copyright>2026 Nick Liu</copyright><lastBuildDate>Sun, 30 Aug 2026 00:52:14 -0700</lastBuildDate><atom:link href="https://nick-liu.com/tags/controlmaster/index.xml" rel="self" type="application/rss+xml"/><item><title>The tunnel was up. The socket existed. Nothing was on the other end.</title><link>https://nick-liu.com/posts/herddeck-ssh-tunnel-lies/</link><pubDate>Thu, 03 Sep 2026 00:00:00 +0000</pubDate><author>nickboy@users.noreply.github.com (Nick Liu)</author><guid>https://nick-liu.com/posts/herddeck-ssh-tunnel-lies/</guid><description>&lt;div class="lead text-neutral-500 dark:text-neutral-400 !mb-9 text-xl"&gt;&#10; &#10;The daemon reported the tunnel as established. The local socket file was right there on disk with the right permissions. The target sat at `offline` forever. Meanwhile `connect to /home/nick/.config/herdr/sessions/main/herdr.sock port 0 failed` was being written to a stderr stream that nothing in my process ever read, several times a second, for as long as I left it running.&#10;&#10;&lt;/div&gt;&#10;&#10;&lt;nav class="series-progress" aria-label="Series progress"&gt;&#10; &lt;span class="series-progress-label"&gt;Deleting ClaudeDeck · Part 5 of 5&lt;/span&gt;&#10; &lt;ol class="series-progress-dots"&gt;&lt;li class="series-progress-dot is-done"&gt;&#10; &lt;a href="https://nick-liu.com/posts/herddeck-substrate-bet/" title="I deleted six subsystems by swapping one dependency. The protocol billed me."&gt;1&lt;/a&gt;&#10; &lt;/li&gt;&lt;li class="series-progress-dot is-done"&gt;&#10; &lt;a href="https://nick-liu.com/posts/herddeck-backoff-wrong-question/" title="My backoff logged errors=1 492 times. It was answering the wrong question."&gt;2&lt;/a&gt;&#10; &lt;/li&gt;&lt;li class="series-progress-dot is-done"&gt;&#10; &lt;a href="https://nick-liu.com/posts/herddeck-frozen-context-ring/" title="Every context ring read 10%. Two bugs, and fixing one hid the other."&gt;3&lt;/a&gt;&#10; &lt;/li&gt;&lt;li class="series-progress-dot is-done"&gt;&#10; &lt;a href="https://nick-liu.com/posts/herddeck-ring-read-backwards/" title="The ring was 1.00:1 against its background. The key read 35% at 65%."&gt;4&lt;/a&gt;&#10; &lt;/li&gt;&lt;li class="series-progress-dot is-current"&gt;&#10; &lt;a href="https://nick-liu.com/posts/herddeck-ssh-tunnel-lies/" title="The tunnel was up. The socket existed. Nothing was on the other end." aria-current="step"&gt;5&lt;/a&gt;&#10; &lt;/li&gt;&lt;/ol&gt;&#10; &lt;/nav&gt;&#10;&lt;div class="tested-with" role="note"&gt;&#10; &lt;span class="tested-with-icon" aria-hidden="true"&gt;🧪&lt;/span&gt;&#10; &lt;span&gt;Tested with &lt;strong&gt;herdr&lt;/strong&gt; &lt;code&gt;0.8.0&lt;/code&gt; · macOS&lt;/span&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;p&gt;HerdDeck drives agents on a second machine. My laptop has the Stream Deck and the daemon; the desktop runs herdr and the agents actually doing work. They are joined by &lt;code&gt;ssh -N -L &amp;lt;local.sock&amp;gt;:&amp;lt;remote.sock&amp;gt; host&lt;/code&gt;, a Unix-domain socket forward, and the daemon speaks the same protocol to a forwarded socket as it does to a local one.&lt;/p&gt;</description><content:encoded>&lt;div class="lead text-neutral-500 dark:text-neutral-400 !mb-9 text-xl"&gt;&#10; &#10;The daemon reported the tunnel as established. The local socket file was right there on disk with the right permissions. The target sat at `offline` forever. Meanwhile `connect to /home/nick/.config/herdr/sessions/main/herdr.sock port 0 failed` was being written to a stderr stream that nothing in my process ever read, several times a second, for as long as I left it running.&#10;&#10;&lt;/div&gt;&#10;&#10;&lt;nav class="series-progress" aria-label="Series progress"&gt;&#10; &lt;span class="series-progress-label"&gt;Deleting ClaudeDeck · Part 5 of 5&lt;/span&gt;&#10; &lt;ol class="series-progress-dots"&gt;&lt;li class="series-progress-dot is-done"&gt;&#10; &lt;a href="https://nick-liu.com/posts/herddeck-substrate-bet/" title="I deleted six subsystems by swapping one dependency. The protocol billed me."&gt;1&lt;/a&gt;&#10; &lt;/li&gt;&lt;li class="series-progress-dot is-done"&gt;&#10; &lt;a href="https://nick-liu.com/posts/herddeck-backoff-wrong-question/" title="My backoff logged errors=1 492 times. It was answering the wrong question."&gt;2&lt;/a&gt;&#10; &lt;/li&gt;&lt;li class="series-progress-dot is-done"&gt;&#10; &lt;a href="https://nick-liu.com/posts/herddeck-frozen-context-ring/" title="Every context ring read 10%. Two bugs, and fixing one hid the other."&gt;3&lt;/a&gt;&#10; &lt;/li&gt;&lt;li class="series-progress-dot is-done"&gt;&#10; &lt;a href="https://nick-liu.com/posts/herddeck-ring-read-backwards/" title="The ring was 1.00:1 against its background. The key read 35% at 65%."&gt;4&lt;/a&gt;&#10; &lt;/li&gt;&lt;li class="series-progress-dot is-current"&gt;&#10; &lt;a href="https://nick-liu.com/posts/herddeck-ssh-tunnel-lies/" title="The tunnel was up. The socket existed. Nothing was on the other end." aria-current="step"&gt;5&lt;/a&gt;&#10; &lt;/li&gt;&lt;/ol&gt;&#10; &lt;/nav&gt;&#10;&lt;div class="tested-with" role="note"&gt;&#10; &lt;span class="tested-with-icon" aria-hidden="true"&gt;🧪&lt;/span&gt;&#10; &lt;span&gt;Tested with &lt;strong&gt;herdr&lt;/strong&gt; &lt;code&gt;0.8.0&lt;/code&gt; · macOS&lt;/span&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;p&gt;HerdDeck drives agents on a second machine. My laptop has the Stream Deck and the daemon; the desktop runs herdr and the agents actually doing work. They are joined by &lt;code&gt;ssh -N -L &amp;lt;local.sock&amp;gt;:&amp;lt;remote.sock&amp;gt; host&lt;/code&gt;, a Unix-domain socket forward, and the daemon speaks the same protocol to a forwarded socket as it does to a local one.&lt;/p&gt;&#10;&lt;p&gt;That symmetry is the entire reason remote support was cheap. It is also what made this bug possible, because &amp;ldquo;I have a socket&amp;rdquo; is a much weaker statement than it looks.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;&lt;code&gt;ssh -L&lt;/code&gt; binds before it connects&#10; &lt;div id="ssh--l-binds-before-it-connects" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ssh--l-binds-before-it-connects" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;A local forward binds the listening end immediately. It does not, and cannot, verify that anything is listening on the far side, because nothing tries to reach the far side until you open a connection through it.&lt;/p&gt;&#10;&lt;p&gt;So the moment &lt;code&gt;ssh -N -L&lt;/code&gt; starts, you have a socket file. It is a real socket. You can &lt;code&gt;connect()&lt;/code&gt; to it. And when you do, ssh opens a channel, asks the remote sshd to reach the target path, the remote sshd fails, and ssh writes a message about it to &lt;em&gt;its&lt;/em&gt; stderr and closes your channel.&lt;/p&gt;&#10;&lt;p&gt;My daemon&amp;rsquo;s definition of &amp;ldquo;established&amp;rdquo; was the existence of that file.&lt;/p&gt;&#10;&lt;p&gt;Every failure mode on the far side therefore looked identical and looked fine. Remote herdr not running: tunnel up, target offline. Wrong absolute path in the config: tunnel up, target offline. Session socket not created because that named session had never been started on the remote: tunnel up, target offline.&lt;/p&gt;&#10;&lt;p&gt;Three different problems, one symptom, and the symptom actively pointed away from the cause, because the tunnel was the part reporting healthy.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;The error was there the whole time&#10; &lt;div id="the-error-was-there-the-whole-time" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#the-error-was-there-the-whole-time" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;The failures are asynchronous. ssh does not fail at spawn; it fails per channel, later, on stderr. I was reading stderr during spawn to catch startup errors, then dropping the stream on the floor once the process was up.&lt;/p&gt;&#10;&lt;p&gt;Everything the debugger needed was in the part I stopped reading.&lt;/p&gt;&#10;&lt;p&gt;Two changes. First, stderr is drained for the tunnel&amp;rsquo;s entire lifetime into a small per-target ring buffer, capped, so a chatty failure cannot grow without bound and the last few dozen lines are always available for diagnostics. Second, and more important, establishing a tunnel now ends by proving it:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bind local socket -&amp;gt; ping-probe THROUGH the socket -&amp;gt; declare established&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;The probe is a real protocol &lt;code&gt;ping&lt;/code&gt; through the forwarded socket with a 4-second timeout. If it fails, the tunnel is not established, regardless of what the filesystem says, and the failure joins the retry path with the stderr tail attached to the error.&lt;/p&gt;&#10;&lt;p&gt;The observable difference is the whole point. Before: tunnel green, target offline indefinitely, zero clues. After: it fails within seconds with &lt;code&gt;channel 1: open failed: connect failed&lt;/code&gt; and the full &lt;code&gt;-L&lt;/code&gt; path mapping in the log, which names the wrong path directly.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;ControlMaster pollution, in both directions&#10; &lt;div id="controlmaster-pollution-in-both-directions" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#controlmaster-pollution-in-both-directions" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;This one I would never have found by reading code, because the bug lived in the interaction between correct code and my personal SSH config.&lt;/p&gt;&#10;&lt;p&gt;Most developers have &lt;code&gt;ControlMaster auto&lt;/code&gt; set. It multiplexes SSH sessions to the same host over one connection, which is why your second &lt;code&gt;ssh&lt;/code&gt; to a box you are already on connects instantly. It is a good default and I have had it on for years.&lt;/p&gt;&#10;&lt;p&gt;A long-lived tunnel joining that multiplexing arrangement fails in two directions, and the second is nastier.&lt;/p&gt;&#10;&lt;div class="not-prose diagram diagram-light"&gt;&lt;svg id="da14699abd285f1b6light" width="100%" xmlns="http://www.w3.org/2000/svg" style="max-width: 878.5px;" viewBox="-50 -10 878.5 421" role="graphics-document document" aria-roledescription="sequence"&gt;&lt;g&gt;&lt;rect x="589" y="335" fill="#eaeaea" stroke="#666" width="150" height="65" name="T" rx="3" ry="3" class="actor actor-bottom"&gt;&lt;/rect&gt;&lt;text x="664" y="367.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="664" dy="0"&gt;herddeck tunnel&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x="272" y="335" fill="#eaeaea" stroke="#666" width="150" height="65" name="M" rx="3" ry="3" class="actor actor-bottom"&gt;&lt;/rect&gt;&lt;text x="347" y="367.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="347" dy="0"&gt;ControlMaster&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x="0" y="335" fill="#eaeaea" stroke="#666" width="150" height="65" name="S" rx="3" ry="3" class="actor actor-bottom"&gt;&lt;/rect&gt;&lt;text x="75" y="367.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="75" dy="0"&gt;your shell&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;line id="actor2" x1="664" y1="65" x2="664" y2="335" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="T" data-et="life-line" data-id="T"&gt;&lt;/line&gt;&lt;g id="root-2" data-et="participant" data-type="participant" data-id="T"&gt;&lt;rect x="589" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="T" rx="3" ry="3" class="actor actor-top"&gt;&lt;/rect&gt;&lt;text x="664" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="664" dy="0"&gt;herddeck tunnel&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g&gt;&lt;line id="actor1" x1="347" y1="65" x2="347" y2="335" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="M" data-et="life-line" data-id="M"&gt;&lt;/line&gt;&lt;g id="root-1" data-et="participant" data-type="participant" data-id="M"&gt;&lt;rect x="272" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="M" rx="3" ry="3" class="actor actor-top"&gt;&lt;/rect&gt;&lt;text x="347" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="347" dy="0"&gt;ControlMaster&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g&gt;&lt;line id="actor0" x1="75" y1="65" x2="75" y2="335" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="S" data-et="life-line" data-id="S"&gt;&lt;/line&gt;&lt;g id="root-0" data-et="participant" data-type="participant" data-id="S"&gt;&lt;rect x="0" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="S" rx="3" ry="3" class="actor actor-top"&gt;&lt;/rect&gt;&lt;text x="75" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="75" dy="0"&gt;your shell&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;style&gt;#da14699abd285f1b6light{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,noto sans,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#da14699abd285f1b6light .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#da14699abd285f1b6light .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#da14699abd285f1b6light .error-icon{fill:rgb(255, 255, 255);}#da14699abd285f1b6light .error-text{fill:#000000;stroke:#000000;}#da14699abd285f1b6light .edge-thickness-normal{stroke-width:1px;}#da14699abd285f1b6light .edge-thickness-thick{stroke-width:3.5px;}#da14699abd285f1b6light .edge-pattern-solid{stroke-dasharray:0;}#da14699abd285f1b6light .edge-thickness-invisible{stroke-width:0;fill:none;}#da14699abd285f1b6light .edge-pattern-dashed{stroke-dasharray:3;}#da14699abd285f1b6light .edge-pattern-dotted{stroke-dasharray:2;}#da14699abd285f1b6light .marker{fill:rgb(74, 86, 92);stroke:rgb(74, 86, 92);}#da14699abd285f1b6light .marker.cross{stroke:rgb(74, 86, 92);}#da14699abd285f1b6light svg{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,noto sans,sans-serif;font-size:16px;}#da14699abd285f1b6light p{margin:0;}#da14699abd285f1b6light .actor{stroke:rgb(204, 216, 222);fill:rgb(255, 255, 255);stroke-width:1;}#da14699abd285f1b6light rect.actor.outer-path[data-look="neo"]{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6light rect.note[data-look="neo"]{stroke:hsl(52.6829268293, 60%, 73.9215686275%);fill:#fff5ad;filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6light text.actor&amp;gt;tspan{fill:#333;stroke:none;}#da14699abd285f1b6light .actor-line{stroke:rgb(204, 216, 222);}#da14699abd285f1b6light .innerArc{stroke-width:1.5;stroke-dasharray:none;}#da14699abd285f1b6light .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#da14699abd285f1b6light .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#da14699abd285f1b6light [id$="-arrowhead"] path{fill:#333;stroke:#333;}#da14699abd285f1b6light .sequenceNumber{fill:#b5a9a3;}#da14699abd285f1b6light [id$="-sequencenumber"]{fill:#333;}#da14699abd285f1b6light [id$="-crosshead"] path{fill:#333;stroke:#333;}#da14699abd285f1b6light .messageText{fill:#333;stroke:none;}#da14699abd285f1b6light .labelBox{stroke:rgb(204, 216, 222);fill:rgb(255, 255, 255);filter:none;}#da14699abd285f1b6light .labelText,#da14699abd285f1b6light .labelText&amp;gt;tspan{fill:#333;stroke:none;}#da14699abd285f1b6light .loopText,#da14699abd285f1b6light .loopText&amp;gt;tspan{fill:#333;stroke:none;}#da14699abd285f1b6light .sectionTitle,#da14699abd285f1b6light .sectionTitle&amp;gt;tspan{fill:#333;stroke:none;}#da14699abd285f1b6light .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:rgb(204, 216, 222);fill:rgb(204, 216, 222);}#da14699abd285f1b6light .note{stroke:hsl(52.6829268293, 60%, 73.9215686275%);fill:#fff5ad;}#da14699abd285f1b6light .noteText,#da14699abd285f1b6light .noteText&amp;gt;tspan{fill:#333;stroke:none;font-weight:normal;}#da14699abd285f1b6light .activation0{fill:rgb(182, 240, 255);stroke:hsl(192.3287671233, 100%, 75.6862745098%);}#da14699abd285f1b6light .activation1{fill:rgb(182, 240, 255);stroke:hsl(192.3287671233, 100%, 75.6862745098%);}#da14699abd285f1b6light .activation2{fill:rgb(182, 240, 255);stroke:hsl(192.3287671233, 100%, 75.6862745098%);}#da14699abd285f1b6light .actorPopupMenu{position:absolute;}#da14699abd285f1b6light .actorPopupMenuPanel{position:absolute;fill:rgb(255, 255, 255);box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#da14699abd285f1b6light .actor-man circle,#da14699abd285f1b6light line{fill:rgb(255, 255, 255);stroke-width:2px;}#da14699abd285f1b6light g rect.rect{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));stroke:rgb(204, 216, 222);}#da14699abd285f1b6light .node .neo-node{stroke:rgb(204, 216, 222);}#da14699abd285f1b6light [data-look="neo"].node rect,#da14699abd285f1b6light [data-look="neo"].cluster rect,#da14699abd285f1b6light [data-look="neo"].node polygon{stroke:url(#da14699abd285f1b6light-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6light [data-look="neo"].swimlane.cluster rect{filter:none;}#da14699abd285f1b6light [data-look="neo"].node path{stroke:url(#da14699abd285f1b6light-gradient);stroke-width:1px;}#da14699abd285f1b6light [data-look="neo"].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6light [data-look="neo"].node .neo-line path{stroke:rgb(204, 216, 222);filter:none;}#da14699abd285f1b6light [data-look="neo"].node circle{stroke:url(#da14699abd285f1b6light-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6light [data-look="neo"].node circle .state-start{fill:#000000;}#da14699abd285f1b6light [data-look="neo"].icon-shape .icon{fill:url(#da14699abd285f1b6light-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6light [data-look="neo"].icon-shape .icon-neo path{stroke:url(#da14699abd285f1b6light-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6light :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}&lt;/style&gt;&lt;g&gt;&lt;/g&gt;&lt;defs&gt;&lt;symbol id="da14699abd285f1b6light-computer" width="24" height="24"&gt;&lt;path transform="scale(.5)" d="M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z"&gt;&lt;/path&gt;&lt;/symbol&gt;&lt;/defs&gt;&lt;defs&gt;&lt;symbol id="da14699abd285f1b6light-database" fill-rule="evenodd" clip-rule="evenodd"&gt;&lt;path transform="scale(.5)" d="M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z"&gt;&lt;/path&gt;&lt;/symbol&gt;&lt;/defs&gt;&lt;defs&gt;&lt;symbol id="da14699abd285f1b6light-clock" width="24" height="24"&gt;&lt;path transform="scale(.5)" d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z"&gt;&lt;/path&gt;&lt;/symbol&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6light-arrowhead" refX="7.9" refY="5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"&gt;&lt;path d="M -1 0 L 10 5 L 0 10 z"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6light-crosshead" markerWidth="15" markerHeight="8" orient="auto" refX="4" refY="4.5"&gt;&lt;path fill="none" stroke="#000000" stroke-width="1pt" d="M 1,2 L 6,7 M 6,2 L 1,7" style="stroke-dasharray: 0, 0;"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6light-filled-head" refX="15.5" refY="7" markerWidth="20" markerHeight="28" orient="auto"&gt;&lt;path d="M 18,7 L9,13 L14,7 L9,1 Z"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6light-sequencenumber" refX="15" refY="15" markerWidth="60" markerHeight="40" orient="auto"&gt;&lt;circle cx="15" cy="15" r="6"&gt;&lt;/circle&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6light-solidTopArrowHead" refX="7.9" refY="7.25" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"&gt;&lt;path d="M 0 0 L 10 8 L 0 8 z"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6light-solidBottomArrowHead" refX="7.9" refY="0.75" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"&gt;&lt;path d="M 0 0 L 10 0 L 0 8 z"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6light-stickTopArrowHead" refX="7.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"&gt;&lt;path d="M 0 0 L 7 7" stroke="black" stroke-width="1.5" fill="none"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6light-stickBottomArrowHead" refX="7.5" refY="0" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"&gt;&lt;path d="M 0 7 L 7 0" stroke="black" stroke-width="1.5" fill="none"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;g data-et="note" data-id="i2"&gt;&lt;rect x="549.5" y="167" fill="#EDF2AE" stroke="#666" width="229" height="56" class="note"&gt;&lt;/rect&gt;&lt;text x="664" y="172" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="noteText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="664"&gt;tunnel now depends on&lt;/tspan&gt;&lt;/text&gt;&lt;text x="664" y="190" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="noteText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="664"&gt;a connection it does not own&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;text x="210" y="80" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;ssh desktop (opens master)&lt;/text&gt;&lt;line x1="76" y1="111" x2="343" y2="111" class="messageLine0" data-et="message" data-id="i0" data-from="S" data-to="M" stroke-width="2" stroke="none" marker-end="url(#da14699abd285f1b6light-arrowhead)" style="fill: none;"&gt;&lt;/line&gt;&lt;text x="507" y="126" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;ssh -N -L (muxes onto master)&lt;/text&gt;&lt;line x1="663" y1="157" x2="351" y2="157" class="messageLine0" data-et="message" data-id="i1" data-from="T" data-to="M" stroke-width="2" stroke="none" marker-end="url(#da14699abd285f1b6light-arrowhead)" style="fill: none;"&gt;&lt;/line&gt;&lt;text x="210" y="238" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;exit&lt;/text&gt;&lt;line x1="76" y1="269" x2="343" y2="269" class="messageLine0" data-et="message" data-id="i3" data-from="S" data-to="M" stroke-width="2" stroke="none" marker-end="url(#da14699abd285f1b6light-arrowhead)" style="fill: none;"&gt;&lt;/line&gt;&lt;text x="504" y="284" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;ControlPersist expires, tunnel dies&lt;/text&gt;&lt;line x1="348" y1="315" x2="660" y2="315" class="messageLine1" data-et="message" data-id="i4" data-from="M" data-to="T" stroke-width="2" stroke="none" marker-end="url(#da14699abd285f1b6light-crosshead)" style="stroke-dasharray: 3, 3; fill: none;"&gt;&lt;/line&gt;&lt;/svg&gt;&lt;/div&gt;&#10; &lt;div class="not-prose diagram diagram-dark"&gt;&lt;svg id="da14699abd285f1b6dark" width="100%" xmlns="http://www.w3.org/2000/svg" style="max-width: 878.5px;" viewBox="-50 -10 878.5 421" role="graphics-document document" aria-roledescription="sequence"&gt;&lt;g&gt;&lt;rect x="589" y="335" fill="#eaeaea" stroke="#666" width="150" height="65" name="T" rx="3" ry="3" class="actor actor-bottom"&gt;&lt;/rect&gt;&lt;text x="664" y="367.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="664" dy="0"&gt;herddeck tunnel&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x="272" y="335" fill="#eaeaea" stroke="#666" width="150" height="65" name="M" rx="3" ry="3" class="actor actor-bottom"&gt;&lt;/rect&gt;&lt;text x="347" y="367.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="347" dy="0"&gt;ControlMaster&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x="0" y="335" fill="#eaeaea" stroke="#666" width="150" height="65" name="S" rx="3" ry="3" class="actor actor-bottom"&gt;&lt;/rect&gt;&lt;text x="75" y="367.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="75" dy="0"&gt;your shell&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;line id="actor5" x1="664" y1="65" x2="664" y2="335" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="T" data-et="life-line" data-id="T"&gt;&lt;/line&gt;&lt;g id="root-5" data-et="participant" data-type="participant" data-id="T"&gt;&lt;rect x="589" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="T" rx="3" ry="3" class="actor actor-top"&gt;&lt;/rect&gt;&lt;text x="664" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="664" dy="0"&gt;herddeck tunnel&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g&gt;&lt;line id="actor4" x1="347" y1="65" x2="347" y2="335" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="M" data-et="life-line" data-id="M"&gt;&lt;/line&gt;&lt;g id="root-4" data-et="participant" data-type="participant" data-id="M"&gt;&lt;rect x="272" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="M" rx="3" ry="3" class="actor actor-top"&gt;&lt;/rect&gt;&lt;text x="347" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="347" dy="0"&gt;ControlMaster&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g&gt;&lt;line id="actor3" x1="75" y1="65" x2="75" y2="335" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="S" data-et="life-line" data-id="S"&gt;&lt;/line&gt;&lt;g id="root-3" data-et="participant" data-type="participant" data-id="S"&gt;&lt;rect x="0" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="S" rx="3" ry="3" class="actor actor-top"&gt;&lt;/rect&gt;&lt;text x="75" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="75" dy="0"&gt;your shell&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;style&gt;#da14699abd285f1b6dark{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,noto sans,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#da14699abd285f1b6dark .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#da14699abd285f1b6dark .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#da14699abd285f1b6dark .error-icon{fill:#a44141;}#da14699abd285f1b6dark .error-text{fill:#ddd;stroke:#ddd;}#da14699abd285f1b6dark .edge-thickness-normal{stroke-width:1px;}#da14699abd285f1b6dark .edge-thickness-thick{stroke-width:3.5px;}#da14699abd285f1b6dark .edge-pattern-solid{stroke-dasharray:0;}#da14699abd285f1b6dark .edge-thickness-invisible{stroke-width:0;fill:none;}#da14699abd285f1b6dark .edge-pattern-dashed{stroke-dasharray:3;}#da14699abd285f1b6dark .edge-pattern-dotted{stroke-dasharray:2;}#da14699abd285f1b6dark .marker{fill:lightgrey;stroke:lightgrey;}#da14699abd285f1b6dark .marker.cross{stroke:lightgrey;}#da14699abd285f1b6dark svg{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,noto sans,sans-serif;font-size:16px;}#da14699abd285f1b6dark p{margin:0;}#da14699abd285f1b6dark .actor{stroke:#ccc;fill:#1f2020;stroke-width:1;}#da14699abd285f1b6dark rect.actor.outer-path[data-look="neo"]{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6dark rect.note[data-look="neo"]{stroke:hsl(180, 0%, 18.3529411765%);fill:hsl(180, 1.5873015873%, 28.3529411765%);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6dark text.actor&amp;gt;tspan{fill:lightgrey;stroke:none;}#da14699abd285f1b6dark .actor-line{stroke:#ccc;}#da14699abd285f1b6dark .innerArc{stroke-width:1.5;stroke-dasharray:none;}#da14699abd285f1b6dark .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:lightgrey;}#da14699abd285f1b6dark .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:lightgrey;}#da14699abd285f1b6dark [id$="-arrowhead"] path{fill:lightgrey;stroke:lightgrey;}#da14699abd285f1b6dark .sequenceNumber{fill:black;}#da14699abd285f1b6dark [id$="-sequencenumber"]{fill:lightgrey;}#da14699abd285f1b6dark [id$="-crosshead"] path{fill:lightgrey;stroke:lightgrey;}#da14699abd285f1b6dark .messageText{fill:lightgrey;stroke:none;}#da14699abd285f1b6dark .labelBox{stroke:#ccc;fill:#1f2020;filter:none;}#da14699abd285f1b6dark .labelText,#da14699abd285f1b6dark .labelText&amp;gt;tspan{fill:lightgrey;stroke:none;}#da14699abd285f1b6dark .loopText,#da14699abd285f1b6dark .loopText&amp;gt;tspan{fill:lightgrey;stroke:none;}#da14699abd285f1b6dark .sectionTitle,#da14699abd285f1b6dark .sectionTitle&amp;gt;tspan{fill:lightgrey;stroke:none;}#da14699abd285f1b6dark .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:#ccc;fill:#ccc;}#da14699abd285f1b6dark .note{stroke:hsl(180, 0%, 18.3529411765%);fill:hsl(180, 1.5873015873%, 28.3529411765%);}#da14699abd285f1b6dark .noteText,#da14699abd285f1b6dark .noteText&amp;gt;tspan{fill:rgb(183.8476190475, 181.5523809523, 181.5523809523);stroke:none;font-weight:normal;}#da14699abd285f1b6dark .activation0{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:#ccc;}#da14699abd285f1b6dark .activation1{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:#ccc;}#da14699abd285f1b6dark .activation2{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:#ccc;}#da14699abd285f1b6dark .actorPopupMenu{position:absolute;}#da14699abd285f1b6dark .actorPopupMenuPanel{position:absolute;fill:#1f2020;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#da14699abd285f1b6dark .actor-man circle,#da14699abd285f1b6dark line{fill:#1f2020;stroke-width:2px;}#da14699abd285f1b6dark g rect.rect{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));stroke:#ccc;}#da14699abd285f1b6dark .node .neo-node{stroke:#ccc;}#da14699abd285f1b6dark [data-look="neo"].node rect,#da14699abd285f1b6dark [data-look="neo"].cluster rect,#da14699abd285f1b6dark [data-look="neo"].node polygon{stroke:url(#da14699abd285f1b6dark-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6dark [data-look="neo"].swimlane.cluster rect{filter:none;}#da14699abd285f1b6dark [data-look="neo"].node path{stroke:url(#da14699abd285f1b6dark-gradient);stroke-width:1px;}#da14699abd285f1b6dark [data-look="neo"].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6dark [data-look="neo"].node .neo-line path{stroke:#ccc;filter:none;}#da14699abd285f1b6dark [data-look="neo"].node circle{stroke:url(#da14699abd285f1b6dark-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6dark [data-look="neo"].node circle .state-start{fill:#000000;}#da14699abd285f1b6dark [data-look="neo"].icon-shape .icon{fill:url(#da14699abd285f1b6dark-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6dark [data-look="neo"].icon-shape .icon-neo path{stroke:url(#da14699abd285f1b6dark-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#da14699abd285f1b6dark :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}&lt;/style&gt;&lt;g&gt;&lt;/g&gt;&lt;defs&gt;&lt;symbol id="da14699abd285f1b6dark-computer" width="24" height="24"&gt;&lt;path transform="scale(.5)" d="M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z"&gt;&lt;/path&gt;&lt;/symbol&gt;&lt;/defs&gt;&lt;defs&gt;&lt;symbol id="da14699abd285f1b6dark-database" fill-rule="evenodd" clip-rule="evenodd"&gt;&lt;path transform="scale(.5)" d="M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z"&gt;&lt;/path&gt;&lt;/symbol&gt;&lt;/defs&gt;&lt;defs&gt;&lt;symbol id="da14699abd285f1b6dark-clock" width="24" height="24"&gt;&lt;path transform="scale(.5)" d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z"&gt;&lt;/path&gt;&lt;/symbol&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6dark-arrowhead" refX="7.9" refY="5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"&gt;&lt;path d="M -1 0 L 10 5 L 0 10 z"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6dark-crosshead" markerWidth="15" markerHeight="8" orient="auto" refX="4" refY="4.5"&gt;&lt;path fill="none" stroke="#000000" stroke-width="1pt" d="M 1,2 L 6,7 M 6,2 L 1,7" style="stroke-dasharray: 0, 0;"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6dark-filled-head" refX="15.5" refY="7" markerWidth="20" markerHeight="28" orient="auto"&gt;&lt;path d="M 18,7 L9,13 L14,7 L9,1 Z"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6dark-sequencenumber" refX="15" refY="15" markerWidth="60" markerHeight="40" orient="auto"&gt;&lt;circle cx="15" cy="15" r="6"&gt;&lt;/circle&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6dark-solidTopArrowHead" refX="7.9" refY="7.25" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"&gt;&lt;path d="M 0 0 L 10 8 L 0 8 z"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6dark-solidBottomArrowHead" refX="7.9" refY="0.75" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"&gt;&lt;path d="M 0 0 L 10 0 L 0 8 z"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6dark-stickTopArrowHead" refX="7.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"&gt;&lt;path d="M 0 0 L 7 7" stroke="black" stroke-width="1.5" fill="none"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id="da14699abd285f1b6dark-stickBottomArrowHead" refX="7.5" refY="0" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"&gt;&lt;path d="M 0 7 L 7 0" stroke="black" stroke-width="1.5" fill="none"&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;g data-et="note" data-id="i2"&gt;&lt;rect x="549.5" y="167" fill="#EDF2AE" stroke="#666" width="229" height="56" class="note"&gt;&lt;/rect&gt;&lt;text x="664" y="172" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="noteText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="664"&gt;tunnel now depends on&lt;/tspan&gt;&lt;/text&gt;&lt;text x="664" y="190" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="noteText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;&lt;tspan x="664"&gt;a connection it does not own&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;text x="210" y="80" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;ssh desktop (opens master)&lt;/text&gt;&lt;line x1="76" y1="111" x2="343" y2="111" class="messageLine0" data-et="message" data-id="i0" data-from="S" data-to="M" stroke-width="2" stroke="none" marker-end="url(#da14699abd285f1b6dark-arrowhead)" style="fill: none;"&gt;&lt;/line&gt;&lt;text x="507" y="126" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;ssh -N -L (muxes onto master)&lt;/text&gt;&lt;line x1="663" y1="157" x2="351" y2="157" class="messageLine0" data-et="message" data-id="i1" data-from="T" data-to="M" stroke-width="2" stroke="none" marker-end="url(#da14699abd285f1b6dark-arrowhead)" style="fill: none;"&gt;&lt;/line&gt;&lt;text x="210" y="238" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;exit&lt;/text&gt;&lt;line x1="76" y1="269" x2="343" y2="269" class="messageLine0" data-et="message" data-id="i3" data-from="S" data-to="M" stroke-width="2" stroke="none" marker-end="url(#da14699abd285f1b6dark-arrowhead)" style="fill: none;"&gt;&lt;/line&gt;&lt;text x="504" y="284" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;"&gt;ControlPersist expires, tunnel dies&lt;/text&gt;&lt;line x1="348" y1="315" x2="660" y2="315" class="messageLine1" data-et="message" data-id="i4" data-from="M" data-to="T" stroke-width="2" stroke="none" marker-end="url(#da14699abd285f1b6dark-crosshead)" style="stroke-dasharray: 3, 3; fill: none;"&gt;&lt;/line&gt;&lt;/svg&gt;&lt;/div&gt;&#10;&lt;p&gt;Direction one: the tunnel dies when an unrelated master connection closes, or when its &lt;code&gt;ControlPersist&lt;/code&gt; timer expires. Your daemon&amp;rsquo;s connectivity is now coupled to whether you happen to have a terminal open.&lt;/p&gt;&#10;&lt;p&gt;Direction two: if the tunnel gets there first, &lt;em&gt;it&lt;/em&gt; becomes the master. Every subsequent interactive &lt;code&gt;ssh&lt;/code&gt; to that host attaches to a connection owned by a background daemon. Restart the daemon and you drop the shells of anyone attached to it.&lt;/p&gt;&#10;&lt;p&gt;The fix is to refuse to participate:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Own the connection lifecycle: with the user&amp;#39;s ControlMaster&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// auto config the tunnel would otherwise mux onto (or become) a&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// shared master and its forward would die with that master&amp;#39;s&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ControlPersist timer (found live in Tier-1 testing).&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;-o&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ControlMaster=no&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;-o&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ControlPath=none&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;-o&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ExitOnForwardFailure=yes&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;A tunnel must own its connection. Borrowing one couples its lifetime to something the daemon does not control and cannot observe.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;Not every failure deserves a retry&#10; &lt;div id="not-every-failure-deserves-a-retry" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#not-every-failure-deserves-a-retry" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;launchd starts the daemon at login, which on a laptop means before Wi-Fi has associated and well before a VPN is up. The first tunnel attempt fails, and in the original code that failure was permanent until I restarted the daemon by hand.&lt;/p&gt;&#10;&lt;p&gt;Retrying everything is the wrong correction. Retrying a wrong passphrase forever is how you get an account locked out, and retrying a host-key mismatch forever is how you sit in a loop ignoring a security warning. So failures get classified by what ssh said:&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ssh stderr contains&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Class&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Behaviour&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Permission denied&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;permanent&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no retry, surfaced as &lt;code&gt;auth&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Host key verification failed&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;permanent&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no retry, surfaced as &lt;code&gt;auth&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Bad configuration&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;permanent&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no retry&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Bad owner or permissions&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;permanent&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no retry&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;everything else&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;transient&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;capped jittered retry, 15s to 10min&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;Connection refused, timeout, network unreachable and DNS resolution failures all default to transient, and DNS is the interesting one. &lt;code&gt;Could not resolve hostname&lt;/code&gt; looks permanent and is completely ambiguous under a VPN that has not come up yet. The default is to retry, because the cost of retrying a genuinely dead hostname is a log line every ten minutes, and the cost of not retrying is a daemon that is dead until you notice.&lt;/p&gt;&#10;&lt;p&gt;The loud error fires once per target rather than once per retry, which is the difference between a diagnostic and a log flood.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;localhost is a valid far side&#10; &lt;div id="localhost-is-a-valid-far-side" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#localhost-is-a-valid-far-side" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;The technique that made most of this testable, and the part I would steal if I were reading someone else&amp;rsquo;s post:&lt;/p&gt;&#10;&lt;p&gt;&amp;ldquo;Remote&amp;rdquo; here means the far side of an ssh streamlocal forward. It does not mean &amp;ldquo;a different machine&amp;rdquo;. Point the forward at &lt;code&gt;localhost&lt;/code&gt; and you get a genuine SSH forward, with a genuine remote sshd, a genuine second herdr socket path, and genuine channel-open failures, on one laptop with no second machine and no network.&lt;/p&gt;&#10;&lt;p&gt;Wrong path, remote daemon down, socket missing, sshd refusing connections, first-connect-before-network: all of those reproduce against sshd on localhost. Only latency and actual link loss need real hardware.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;One caveat about &lt;code&gt;--remote&lt;/code&gt;, because the obvious guess is wrong&#10; &lt;div id="one-caveat-about---remote-because-the-obvious-guess-is-wrong" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#one-caveat-about---remote-because-the-obvious-guess-is-wrong" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;herdr has a &lt;code&gt;--remote&lt;/code&gt; flag and it does not do what you would assume from the outside.&lt;/p&gt;&#10;&lt;p&gt;It makes the &lt;em&gt;human&lt;/em&gt; terminal experience a thin client. It does not expose a local API socket that proxies the remote server. The local &lt;code&gt;herdr-client.sock&lt;/code&gt; is a TUI attach endpoint, so a daemon cannot piggyback on it and needs its own forward.&lt;/p&gt;&#10;&lt;p&gt;There is a consequence to that which bit me later. herdr auto-syncs versions between client and server, and that sync fires on a human &lt;code&gt;--remote&lt;/code&gt; attach. It never fires for the daemon&amp;rsquo;s forward. So a machine you rarely attach to by hand can quietly drift to an older protocol while the daemon happily keeps talking to it. Every target is therefore pinged and version-checked on connect and degraded to a warning state on mismatch, rather than assumed compatible.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;When not to guess&#10; &lt;div id="when-not-to-guess" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#when-not-to-guess" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;I want to end on the one place in this system where the correct behaviour is to do nothing, because multi-target is what creates it.&lt;/p&gt;&#10;&lt;p&gt;Each herdr server tracks its own focused pane. With two targets connected, two panes can each legitimately report that the user is looking at them, and the daemon has no way to know which screen you are actually in front of.&lt;/p&gt;&#10;&lt;p&gt;The physical Enter key sends a keystroke to the focused agent. Guessing wrong there does not display something incorrect. It submits someone else&amp;rsquo;s prompt, to a different agent, on a different machine, with whatever half-written text was sitting in that pane.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;getFocusedAgent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AgentSnapshot&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;focused&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agentsList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sameAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;focused&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;herdrFocused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agentsList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;focused&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// More than one target can each report a focused pane; only an&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// unambiguous single candidate is safe to act on.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;herdrFocused&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;herdrFocused&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;An explicit slot press always wins, because that is you telling it. Absent that, one candidate is a fallback and two candidates is nothing. The refusal has its own test, with the reasoning written into the test body, because it is the kind of behaviour a future refactor would happily &amp;ldquo;fix&amp;rdquo; into a &lt;code&gt;[0]&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;Lessons&#10; &lt;div id="lessons" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lessons" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;A bound socket is not a connected socket. &lt;code&gt;ssh -L&lt;/code&gt; binds before anything reaches the far end, so the file existing proves only that ssh started.&lt;/li&gt;&#10;&lt;li&gt;End every &amp;ldquo;establish&amp;rdquo; with a probe that exercises the thing you are claiming works. Reachability is the claim, so make a round trip and let that be the definition.&lt;/li&gt;&#10;&lt;li&gt;If a process fails asynchronously on stderr, drain stderr for its whole life. Reading it only at startup means the exact bytes naming your bug are being written and discarded while you debug.&lt;/li&gt;&#10;&lt;li&gt;A long-lived tunnel must own its SSH connection. Muxing onto a user&amp;rsquo;s ControlMaster couples the daemon to a terminal, and winning the race to become the master is worse, because now your restart drops their shells.&lt;/li&gt;&#10;&lt;li&gt;Classify failures before retrying them. Auth and host-key failures should never retry; timeouts, refusals and DNS should, because DNS under a sleeping VPN is indistinguishable from DNS against a dead host.&lt;/li&gt;&#10;&lt;li&gt;Log the loud error once per target, not once per retry. A diagnostic that repeats every fifteen seconds is a log flood that people filter out.&lt;/li&gt;&#10;&lt;li&gt;localhost is a valid far side. Most of a remote-path test matrix runs against sshd on the same machine, and only latency and link loss need real hardware.&lt;/li&gt;&#10;&lt;li&gt;When ambiguity could take a destructive action, do nothing and test that you do nothing. Sending Enter to the wrong agent submits someone else&amp;rsquo;s prompt.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&lt;h2 class="relative group"&gt;References&#10; &lt;div id="references" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#references" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;ssh_config(5)&lt;/code&gt; for &lt;code&gt;ControlMaster&lt;/code&gt;, &lt;code&gt;ControlPath&lt;/code&gt;, &lt;code&gt;ControlPersist&lt;/code&gt; and &lt;code&gt;ExitOnForwardFailure&lt;/code&gt;; &lt;code&gt;ssh(1)&lt;/code&gt; for &lt;code&gt;-L&lt;/code&gt; and streamlocal forwarding&lt;/li&gt;&#10;&lt;li&gt;OpenSSH release notes on Unix-domain socket forwarding: &lt;a href="https://www.openssh.com/txt/release-6.7" target="_blank" rel="noreferrer"&gt;https://www.openssh.com/txt/release-6.7&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;herdr: &lt;a href="https://herdr.dev" target="_blank" rel="noreferrer"&gt;https://herdr.dev&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;The rebuild that made remote almost free: &lt;a href="https://nick-liu.com/posts/herddeck-substrate-bet/" &gt;I deleted six subsystems by swapping one dependency.&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;HerdDeck tunnel manager, ssh args, stderr ring and the probe: &lt;a href="https://github.com/nickboy/herddeck/blob/main/packages/daemon/src/tunnel.ts" target="_blank" rel="noreferrer"&gt;&lt;code&gt;packages/daemon/src/tunnel.ts&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;HerdDeck registry, retry classification and backoff: &lt;a href="https://github.com/nickboy/herddeck/blob/main/packages/daemon/src/registry.ts" target="_blank" rel="noreferrer"&gt;&lt;code&gt;packages/daemon/src/registry.ts&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;Remote-path static review findings: &lt;a href="https://github.com/nickboy/herddeck/blob/main/docs/plans/2026-08-08-remote-path-review.md" target="_blank" rel="noreferrer"&gt;&lt;code&gt;docs/plans/2026-08-08-remote-path-review.md&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</content:encoded></item></channel></rss>