···243243### Debug ssh
244244245245When a workflow fails, spindle can keep its microVM alive for a configured grace
246246-window (`MicroVMPipelines.SSH`) and print an `ssh` invocation so you can poke at
247247-the failed VM interactively. Spindle terminates the ssh connection itself and
248248-bridges a pty into the live guest over the agent's vsock; the guest stays
249249-keyless and never runs an ssh daemon.
246246+window (`MicroVMPipelines.DebugSSH.GracePeriod`) and print an `ssh` invocation
247247+so you can poke at the failed VM interactively. Spindle terminates the ssh
248248+connection itself and bridges a pty into the live guest over the agent's
249249+vsock; the guest stays keyless and never runs an ssh daemon.
250250251251Access mirrors a git push: the ssh username is the job id, and the offered
252252public key is sent to the job's repo knot (`sh.tangled.repo.checkPushAllowed`).
253253The session is accepted only if that key is allowed to push to the job's repo.
254254+255255+In a mill fleet, the printed command can use `ssh -J` through the mill's
256256+restricted jump listener. The inner SSH connection still terminates on the
257257+executor, so the mill only forwards an encrypted TCP stream to a live,
258258+operator-registered executor route.
259259+260260+`SPINDLE_MILL_MAX_JUMP_CONNECTIONS` limits concurrent outer SSH connections.
261261+262262+Configure each executor's debug host as its registered executor name. The jump
263263+listener checks that the name has a live authenticated mill session and dials
264264+it on the configured private debug port. The registered name must therefore
265265+resolve on the mill's private network.
254266255267The shell is deliberately not configurable from either end. It always:
256268- runs as the `spindle-workflow` user (the ssh username selects the *job*, not a