`getRecentExpiredSshLease` compared the stored lease ptyId (relay form,
written through `toStoredPtyId` -> `toRelaySshPtyId`) raw against the
runtime's app-form `pty.ptyId`, so `'pty-3' === 'ssh:target@@pty-3'` never
held and `recoverTerminalPane` refused every real SSH pane. Normalize with
the same tolerant helper the binding reader already uses, now shared as
`toComparableRelaySshPtyId`.
Switching the path on is only safe on top of #17957 (respawn gated on the
runtime liveness verdict), #17965 (`expired` no longer withdraws bindings)
and #17966 (supersession and id recycling carry their own marks).
`recoverTerminalPane` additionally refuses a lease those marks disqualify,
so it acts only on an `expired` lease that means "reattach gave up".
The path's outcome is a reattach, not a respawn: `createTerminal` calls
`adoptStablePane` first, which attaches attach-only to the retained
binding and only falls through to a fresh shell once the host itself
answers that the PTY is absent.
* Robustify SSH terminal reconnect and session restore recovery
- Release the replay guard after a fallback timeout to prevent permanent
keyboard input lockouts when an unmounted terminal never parses.
- Verify backing process liveness on PTY attach and reap stale entries
so dead shells cleanly trigger a fresh pane spawn.
- Normalize connection IDs during restore to prevent spurious mismatch
errors, and treat true mismatches as expired sessions instead of crashing.
* Route disconnected SSH terminal panes through deferred connection gate
Avoid spawning SSH terminal processes against disconnected targets,
which otherwise throws "No PTY provider" and leaves panes stranded.
- Intercept spawning via a new connect gate that triggers the deferred
connection flow when the SSH target is disconnected.
- Fall back to composite worktree IDs during cold-start hydration to
ensure deferred SSH session IDs are properly stashed.
- Retry spawning and remounting terminal panes upon SSH reconnect if
they are stranded or failed to spawn.