Repository navigation
Conversation
This PR fixes a real session-routing bug in the desktop gateway layer: when the primary gateway socket is already owned by a registry connection, requesting a gateway for the same A few concerns:
|
|
@Enough1122 Thanks for the review. I audited these points against final head
The follow-up commits also expanded coverage across request/open/ensure and resumed-session send routing. Current focused final-head verification passes 108/108 tests. Supplementary sanitized Apple Silicon validation against a registry-backed remote connection loaded existing history, followed live activity in place, and completed resumed-session sends both before and after navigation without another |
…nsport-error recovery Salvage of #94192's unique work (owner-hardening portions that overlap the class-1 branch — #94824/#93451 seams — and out-of-cluster #94864 are intentionally excluded): - use-gateway-request: recognize the full transport-error family (ECONNRESET & friends, including error.code and error.cause.code) so a reset SSH/remote socket triggers the connection-owned reconnect instead of surfacing as a request failure; background profiles keep the registry reconnect path for composite remote/SSH sources. - session-tile-actions: tile attachment uploads and session RPCs follow the tile's composite owner (connectionId+profile) even when the active gateway moved to a same-named profile on another source. - knownSessionOwner: sessions expose their complete owner (registry connection + profile) instead of a bare profile name that silently collapsed the route back to the local path; delegate/wiring resolve owners through it. Fixes the SSH-reconnect share of #91365-adjacent routing gaps. Salvaged (partial) from #94192.
…nsport-error recovery Salvage of #94192's unique work (owner-hardening portions that overlap the class-1 branch — #94824/#93451 seams — and out-of-cluster #94864 are intentionally excluded): - use-gateway-request: recognize the full transport-error family (ECONNRESET & friends, including error.code and error.cause.code) so a reset SSH/remote socket triggers the connection-owned reconnect instead of surfacing as a request failure; background profiles keep the registry reconnect path for composite remote/SSH sources. - session-tile-actions: tile attachment uploads and session RPCs follow the tile's composite owner (connectionId+profile) even when the active gateway moved to a same-named profile on another source. - knownSessionOwner: sessions expose their complete owner (registry connection + profile) instead of a bare profile name that silently collapsed the route back to the local path; delegate/wiring resolve owners through it. Fixes the SSH-reconnect share of #91365-adjacent routing gaps. Salvaged (partial) from #94192.
…nsport-error recovery Salvage of #94192's unique work (owner-hardening portions that overlap the class-1 branch — #94824/#93451 seams — and out-of-cluster #94864 are intentionally excluded): - use-gateway-request: recognize the full transport-error family (ECONNRESET & friends, including error.code and error.cause.code) so a reset SSH/remote socket triggers the connection-owned reconnect instead of surfacing as a request failure; background profiles keep the registry reconnect path for composite remote/SSH sources. - session-tile-actions: tile attachment uploads and session RPCs follow the tile's composite owner (connectionId+profile) even when the active gateway moved to a same-named profile on another source. - knownSessionOwner: sessions expose their complete owner (registry connection + profile) instead of a bare profile name that silently collapsed the route back to the local path; delegate/wiring resolve owners through it. Fixes the SSH-reconnect share of #91365-adjacent routing gaps. Salvaged (partial) from #94192.
|
Merged via #95080 at 682a34a — your commit was cherry-picked into the consolidated salvage PR with authorship preserved, so this work carries your name in git history. Thanks for the registry-primary reuse for owned session RPCs — clean scoping of which connection answers for an owned session. Closing this original PR now that the consolidated branch has landed on main. Thanks for contributing to the desktop multi-gateway campaign (tracker: #94724). |
…nsport-error recovery Salvage of NousResearch#94192's unique work (owner-hardening portions that overlap the class-1 branch — NousResearch#94824/NousResearch#93451 seams — and out-of-cluster NousResearch#94864 are intentionally excluded): - use-gateway-request: recognize the full transport-error family (ECONNRESET & friends, including error.code and error.cause.code) so a reset SSH/remote socket triggers the connection-owned reconnect instead of surfacing as a request failure; background profiles keep the registry reconnect path for composite remote/SSH sources. - session-tile-actions: tile attachment uploads and session RPCs follow the tile's composite owner (connectionId+profile) even when the active gateway moved to a same-named profile on another source. - knownSessionOwner: sessions expose their complete owner (registry connection + profile) instead of a bare profile name that silently collapsed the route back to the local path; delegate/wiring resolve owners through it. Fixes the SSH-reconnect share of NousResearch#91365-adjacent routing gaps. Salvaged (partial) from NousResearch#94192.
…nsport-error recovery Salvage of NousResearch#94192's unique work (owner-hardening portions that overlap the class-1 branch — NousResearch#94824/NousResearch#93451 seams — and out-of-cluster NousResearch#94864 are intentionally excluded): - use-gateway-request: recognize the full transport-error family (ECONNRESET & friends, including error.code and error.cause.code) so a reset SSH/remote socket triggers the connection-owned reconnect instead of surfacing as a request failure; background profiles keep the registry reconnect path for composite remote/SSH sources. - session-tile-actions: tile attachment uploads and session RPCs follow the tile's composite owner (connectionId+profile) even when the active gateway moved to a same-named profile on another source. - knownSessionOwner: sessions expose their complete owner (registry connection + profile) instead of a bare profile name that silently collapsed the route back to the local path; delegate/wiring resolve owners through it. Fixes the SSH-reconnect share of NousResearch#91365-adjacent routing gaps. Salvaged (partial) from NousResearch#94192.
Summary
requestGatewayForAgenttargets the exact same(connectionId, profile)ownerProblem
requestGatewayForAgentcurrently treats every explicitconnectionIdas requiring a registry secondary. That is wrong when the selected remote registry connection is already the window primary: the durable session's owner metadata points back to the socket that is already open.The duplicate helper dial can resolve the public endpoint through a different backend/profile route. The result is a split symptom: REST history from the primary renders correctly, while
session.resumeon the helper returnssession not foundand the live transcript remains static.This was reproduced against clean current
mainwith a focused regression test: the owner-matched resume went to a newly-created secondary and never called the primary. The observed macOS trace independently showed the same shape: correct durable stored ID,session.resumereturning4007 session not found, and a short-lived helper WebSocket; the same stored ID resumed successfully through the existing primary connection.Fix
The gateway registry now remembers the primary descriptor's
connectionId.requestGatewayForAgentcollapses torequestGatewayForProfileonly when both owner dimensions match:connectionIdequals the primary's published registry sourceUnknown identity, a different source, or a different profile keeps the existing isolated-secondary behavior. Changing the primary gateway clears the remembered identity before a new descriptor is published.
Related work / duplicate check
This is complementary rather than duplicative:
requestGatewayForAgentand therefore still creates the duplicate helper.requestGatewayForAgent.Related symptom family: #93888. This patch addresses the durable-ID/helper-route variant, not that issue's reported cross-gateway runtime-ID leak.
Verification
main: primary request count0, helper createduse-session-actions.test.tsx)npm run typecheckgit diff --checkgateway-settings.test.tsxcollectionSTACK_TRACE_ERRORreproduces unchanged on pristineorigin/mainRisk
Low and fail-closed. Primary reuse requires exact source and profile equality; all ambiguous or cross-profile routes preserve their prior secondary isolation. No backend protocol, persistence schema, credentials, or network configuration changes.
External macOS validation (sanitized)
A source-built Apple Silicon client at final head
ed4f3c73e9bd9fcd7661237a8a38dd2ca2e29261was validated against a generic registry-backed remote connection using profiledefault:session not foundresponse or RPC error was observed during either sendThis is supplementary end-to-end evidence for the registry-owner route; it does not introduce a gateway-specific assumption into the implementation or tests.