fix(navigation): clear daemon state on local handoff
- commit
- ec147af352de9baeba1dbb6aeda31899131d0165
- author
- brice · · 2026-08-11 12:55 UTC
- committer
- brice · · 2026-08-11 12:56 UTC
- parent
- 09015bc
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +48 -0
M internal/usecase/client/routes.go +8 -0
| @@ -557,6 +557,10 @@ func (l *routeLedger) samePeerHandoff(active AttachRequest, target ports.AttachT | |||
| 557 | 557 | // original discovery target would make its Hello request a second, | |
| 558 | 558 | // incorrect remote handoff instead of a same-peer session switch. | |
| 559 | 559 | request.RemoteTarget = nil | |
| 560 | + | if request.EnvironmentPolicy != environmentPolicy && environmentPolicy == ports.EnvironmentPolicyClientOwned { | |
| 561 | + | request.NavigationCapabilities = 0 | |
| 562 | + | request.StartupOverlay = ports.StartupOverlayNone | |
| 563 | + | } | |
| 560 | 564 | request.EnvironmentPolicy = environmentPolicy | |
| 561 | 565 | request.ExactTarget = target.ExactTarget | |
| 562 | 566 | if target.ExactTarget == nil { | |
| @@ -571,6 +575,10 @@ func (l *routeLedger) samePeerHandoff(active AttachRequest, target ports.AttachT | |||
| 571 | 575 | request.ExactTarget = target.ExactTarget | |
| 572 | 576 | request.PreferredTabID = "" | |
| 573 | 577 | request.RemoteTarget = nil | |
| 578 | + | if request.EnvironmentPolicy != environmentPolicy && environmentPolicy == ports.EnvironmentPolicyClientOwned { | |
| 579 | + | request.NavigationCapabilities = 0 | |
| 580 | + | request.StartupOverlay = ports.StartupOverlayNone | |
| 581 | + | } | |
| 574 | 582 | request.EnvironmentPolicy = environmentPolicy | |
| 575 | 583 | return request | |
| 576 | 584 | } | |
| @@ -557,6 +557,10 @@ func (l *routeLedger) samePeerHandoff(active AttachRequest, target ports.AttachT | |||||
| 557 | // original discovery target would make its Hello request a second, | 557 | // original discovery target would make its Hello request a second, | ||
| 558 | // incorrect remote handoff instead of a same-peer session switch. | 558 | // incorrect remote handoff instead of a same-peer session switch. | ||
| 559 | request.RemoteTarget = nil | 559 | request.RemoteTarget = nil | ||
| 560 | + | if request.EnvironmentPolicy != environmentPolicy && environmentPolicy == ports.EnvironmentPolicyClientOwned { | |||
| 561 | + | request.NavigationCapabilities = 0 | |||
| 562 | + | request.StartupOverlay = ports.StartupOverlayNone | |||
| 563 | + | } | |||
| 560 | request.EnvironmentPolicy = environmentPolicy | 564 | request.EnvironmentPolicy = environmentPolicy | ||
| 561 | request.ExactTarget = target.ExactTarget | 565 | request.ExactTarget = target.ExactTarget | ||
| 562 | if target.ExactTarget == nil { | 566 | if target.ExactTarget == nil { | ||
| @@ -571,6 +575,10 @@ func (l *routeLedger) samePeerHandoff(active AttachRequest, target ports.AttachT | |||||
| 571 | request.ExactTarget = target.ExactTarget | 575 | request.ExactTarget = target.ExactTarget | ||
| 572 | request.PreferredTabID = "" | 576 | request.PreferredTabID = "" | ||
| 573 | request.RemoteTarget = nil | 577 | request.RemoteTarget = nil | ||
| 578 | + | if request.EnvironmentPolicy != environmentPolicy && environmentPolicy == ports.EnvironmentPolicyClientOwned { | |||
| 579 | + | request.NavigationCapabilities = 0 | |||
| 580 | + | request.StartupOverlay = ports.StartupOverlayNone | |||
| 581 | + | } | |||
| 574 | request.EnvironmentPolicy = environmentPolicy | 582 | request.EnvironmentPolicy = environmentPolicy | ||
| 575 | return request | 583 | return request | ||
| 576 | } | 584 | } | ||
M internal/usecase/client/routes_test.go +40 -0
| @@ -148,6 +148,46 @@ func TestRouteLedgerSamePeerHandoffRestoresRouteTab(t *testing.T) { | |||
| 148 | 148 | } | |
| 149 | 149 | } | |
| 150 | 150 | ||
| 151 | + | func TestRouteLedgerSamePeerHandoffClearsDaemonOwnedNavigationForLocalRoutes(t *testing.T) { | |
| 152 | + | active := routeTestCandidate(2, ports.RouteOriginLocal) | |
| 153 | + | active.originKey = "local" | |
| 154 | + | active.request.EnvironmentPolicy = ports.EnvironmentPolicyDaemonOwned | |
| 155 | + | active.request.NavigationCapabilities = ports.NavigationCapabilityHomePicker | |
| 156 | + | active.request.StartupOverlay = ports.StartupOverlaySessionPicker | |
| 157 | + | ||
| 158 | + | for _, tt := range []struct { | |
| 159 | + | name string | |
| 160 | + | matched bool | |
| 161 | + | }{ | |
| 162 | + | {name: "matched route", matched: true}, | |
| 163 | + | {name: "fallback route"}, | |
| 164 | + | } { | |
| 165 | + | t.Run(tt.name, func(t *testing.T) { | |
| 166 | + | ledger := newRouteLedger() | |
| 167 | + | target := routeTestTarget(1) | |
| 168 | + | if tt.matched { | |
| 169 | + | stored := routeTestCandidate(1, ports.RouteOriginLocal) | |
| 170 | + | stored.originKey = "local" | |
| 171 | + | stored.request.EnvironmentPolicy = ports.EnvironmentPolicyDaemonOwned | |
| 172 | + | stored.request.NavigationCapabilities = ports.NavigationCapabilityHomePicker | |
| 173 | + | stored.request.StartupOverlay = ports.StartupOverlaySessionPicker | |
| 174 | + | _, err := ledger.commit(stored) | |
| 175 | + | require.NoError(t, err) | |
| 176 | + | } | |
| 177 | + | ||
| 178 | + | request := ledger.samePeerHandoff(active.request, ports.AttachTarget{ | |
| 179 | + | Session: target.SessionName, Intent: ports.IntentAttach, ExactTarget: &target, | |
| 180 | + | EnvironmentPolicy: ports.EnvironmentPolicyDaemonOwned, | |
| 181 | + | }) | |
| 182 | + | ||
| 183 | + | require.Equal(t, ports.EnvironmentPolicyClientOwned, request.EnvironmentPolicy) | |
| 184 | + | require.Zero(t, request.NavigationCapabilities) | |
| 185 | + | require.Equal(t, ports.StartupOverlayNone, request.StartupOverlay) | |
| 186 | + | require.NoError(t, validateAttachRequest(request)) | |
| 187 | + | }) | |
| 188 | + | } | |
| 189 | + | } | |
| 190 | + | ||
| 151 | 191 | func TestRouteLedgerSamePeerHandoffDropsOriginalRemoteTarget(t *testing.T) { | |
| 152 | 192 | ledger := newRouteLedger() | |
| 153 | 193 | work := routeTestCandidate(1, ports.RouteOriginRemote) | |
| @@ -148,6 +148,46 @@ func TestRouteLedgerSamePeerHandoffRestoresRouteTab(t *testing.T) { | |||||
| 148 | } | 148 | } | ||
| 149 | } | 149 | } | ||
| 150 | 150 | ||||
| 151 | + | func TestRouteLedgerSamePeerHandoffClearsDaemonOwnedNavigationForLocalRoutes(t *testing.T) { | |||
| 152 | + | active := routeTestCandidate(2, ports.RouteOriginLocal) | |||
| 153 | + | active.originKey = "local" | |||
| 154 | + | active.request.EnvironmentPolicy = ports.EnvironmentPolicyDaemonOwned | |||
| 155 | + | active.request.NavigationCapabilities = ports.NavigationCapabilityHomePicker | |||
| 156 | + | active.request.StartupOverlay = ports.StartupOverlaySessionPicker | |||
| 157 | + | ||||
| 158 | + | for _, tt := range []struct { | |||
| 159 | + | name string | |||
| 160 | + | matched bool | |||
| 161 | + | }{ | |||
| 162 | + | {name: "matched route", matched: true}, | |||
| 163 | + | {name: "fallback route"}, | |||
| 164 | + | } { | |||
| 165 | + | t.Run(tt.name, func(t *testing.T) { | |||
| 166 | + | ledger := newRouteLedger() | |||
| 167 | + | target := routeTestTarget(1) | |||
| 168 | + | if tt.matched { | |||
| 169 | + | stored := routeTestCandidate(1, ports.RouteOriginLocal) | |||
| 170 | + | stored.originKey = "local" | |||
| 171 | + | stored.request.EnvironmentPolicy = ports.EnvironmentPolicyDaemonOwned | |||
| 172 | + | stored.request.NavigationCapabilities = ports.NavigationCapabilityHomePicker | |||
| 173 | + | stored.request.StartupOverlay = ports.StartupOverlaySessionPicker | |||
| 174 | + | _, err := ledger.commit(stored) | |||
| 175 | + | require.NoError(t, err) | |||
| 176 | + | } | |||
| 177 | + | ||||
| 178 | + | request := ledger.samePeerHandoff(active.request, ports.AttachTarget{ | |||
| 179 | + | Session: target.SessionName, Intent: ports.IntentAttach, ExactTarget: &target, | |||
| 180 | + | EnvironmentPolicy: ports.EnvironmentPolicyDaemonOwned, | |||
| 181 | + | }) | |||
| 182 | + | ||||
| 183 | + | require.Equal(t, ports.EnvironmentPolicyClientOwned, request.EnvironmentPolicy) | |||
| 184 | + | require.Zero(t, request.NavigationCapabilities) | |||
| 185 | + | require.Equal(t, ports.StartupOverlayNone, request.StartupOverlay) | |||
| 186 | + | require.NoError(t, validateAttachRequest(request)) | |||
| 187 | + | }) | |||
| 188 | + | } | |||
| 189 | + | } | |||
| 190 | + | ||||
| 151 | func TestRouteLedgerSamePeerHandoffDropsOriginalRemoteTarget(t *testing.T) { | 191 | func TestRouteLedgerSamePeerHandoffDropsOriginalRemoteTarget(t *testing.T) { | ||
| 152 | ledger := newRouteLedger() | 192 | ledger := newRouteLedger() | ||
| 153 | work := routeTestCandidate(1, ports.RouteOriginRemote) | 193 | work := routeTestCandidate(1, ports.RouteOriginRemote) | ||