bb3421bf25
reconnectGateway()'s in-flight lock lives at renderer module scope, so it only dedupes reconnects inside ONE window. Two windows racing the same wake both invoke the main-process backend ensure IPC, and for a pooled SSH connection the loser of the pool-entry race could bootstrap a duplicate remote backend (two tunnels, two remote serve processes). Electron main is the single owner of backend lifecycles, so the claim now lives there: BackendDialClaims keys in-flight dials by the pool scope key from backendScopeKey(connectionId, profile) — the composite identity seam wave-1 #93189 established for effective-identity reuse. 'hermes:connection' and 'hermes:connection:for' route through backendDialClaims.run(), so concurrent renderer dials for one scope coalesce onto one spawn and the second caller receives the first's result. A claim exists only while its dial promise is unsettled: both outcomes release it, a failed dial is never cached (fail closed, not latched), and a synchronously-throwing dial rejects the claim instead of escaping the seam. The #93910 resume rebuild re-dials retired pool keys through the same claim (redialPoolBackendAfterResume + new parseBackendScopeKey), so a resume-driven rebuild and a concurrent renderer reconnect also coalesce instead of racing.