detached 08343ae

fix(routes): preserve same remote handoffs

commit
08343ae96c593d8dd6005399d3f1c090e46e326f
author
brice · · 2026-08-11 08:37 UTC
parent
11bc196
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +37 -0
M internal/usecase/client/routes.go +4 -0
@@ -549,6 +549,10 @@ func (l *routeLedger) samePeerHandoff(active AttachRequest, target ports.AttachT
549549 }
550550 request := cloneAttachRequest(entry.request)
551551 request.Intent = target.Intent
552+ // The active dialer already reaches this daemon. Retaining the route's
553+ // original discovery target would make its Hello request a second,
554+ // incorrect remote handoff instead of a same-peer session switch.
555+ request.RemoteTarget = nil
552556 request.EnvironmentPolicy = target.EnvironmentPolicy
553557 request.ExactTarget = target.ExactTarget
554558 if target.ExactTarget == nil {
@@ -549,6 +549,10 @@ func (l *routeLedger) samePeerHandoff(active AttachRequest, target ports.AttachT
549 }549 }
550 request := cloneAttachRequest(entry.request)550 request := cloneAttachRequest(entry.request)
551 request.Intent = target.Intent551 request.Intent = target.Intent
552+ // The active dialer already reaches this daemon. Retaining the route's
553+ // original discovery target would make its Hello request a second,
554+ // incorrect remote handoff instead of a same-peer session switch.
555+ request.RemoteTarget = nil
552 request.EnvironmentPolicy = target.EnvironmentPolicy556 request.EnvironmentPolicy = target.EnvironmentPolicy
553 request.ExactTarget = target.ExactTarget557 request.ExactTarget = target.ExactTarget
554 if target.ExactTarget == nil {558 if target.ExactTarget == nil {
M internal/usecase/client/routes_test.go +33 -0
@@ -148,6 +148,39 @@ func TestRouteLedgerSamePeerHandoffRestoresRouteTab(t *testing.T) {
148148 }
149149 }
150150
151+func TestRouteLedgerSamePeerHandoffDropsOriginalRemoteTarget(t *testing.T) {
152+ ledger := newRouteLedger()
153+ work := routeTestCandidate(1, ports.RouteOriginRemote)
154+ work.originKey = "remote"
155+ work.request.Remote = true
156+ work.request.OriginKey = "remote"
157+ work.request.EnvironmentPolicy = ports.EnvironmentPolicyDaemonOwned
158+ work.request.RemoteTarget = &domain.RemoteSessionTarget{
159+ Endpoint: "remote", DisplayOrigin: "remote", LifecycleID: work.target.LifecycleID,
160+ SessionName: work.target.SessionName, LiveTabID: "tab-work",
161+ }
162+ _, err := ledger.commit(work)
163+ require.NoError(t, err)
164+
165+ agents := routeTestCandidate(2, ports.RouteOriginRemote)
166+ agents.originKey = "remote"
167+ agents.request.Remote = true
168+ agents.request.OriginKey = "remote"
169+ agents.request.EnvironmentPolicy = ports.EnvironmentPolicyDaemonOwned
170+
171+ request := ledger.samePeerHandoff(agents.request, ports.AttachTarget{
172+ Session: work.target.SessionName,
173+ Intent: ports.IntentAttach,
174+ ExactTarget: &work.target,
175+ EnvironmentPolicy: ports.EnvironmentPolicyDaemonOwned,
176+ })
177+
178+ require.True(t, request.Remote)
179+ require.Equal(t, ports.RouteOriginRemote, request.Origin)
180+ require.Equal(t, "remote", request.OriginKey)
181+ require.Nil(t, request.RemoteTarget)
182+}
183+
151184 func TestRouteAttentionSubscriptionIncludesOnlyActiveOriginRoutes(t *testing.T) {
152185 ledger := newRouteLedger()
153186 first := routeTestCandidate(0, ports.RouteOriginRemote)
@@ -148,6 +148,39 @@ func TestRouteLedgerSamePeerHandoffRestoresRouteTab(t *testing.T) {
148 }148 }
149 }149 }
150 150
151+func TestRouteLedgerSamePeerHandoffDropsOriginalRemoteTarget(t *testing.T) {
152+ ledger := newRouteLedger()
153+ work := routeTestCandidate(1, ports.RouteOriginRemote)
154+ work.originKey = "remote"
155+ work.request.Remote = true
156+ work.request.OriginKey = "remote"
157+ work.request.EnvironmentPolicy = ports.EnvironmentPolicyDaemonOwned
158+ work.request.RemoteTarget = &domain.RemoteSessionTarget{
159+ Endpoint: "remote", DisplayOrigin: "remote", LifecycleID: work.target.LifecycleID,
160+ SessionName: work.target.SessionName, LiveTabID: "tab-work",
161+ }
162+ _, err := ledger.commit(work)
163+ require.NoError(t, err)
164+
165+ agents := routeTestCandidate(2, ports.RouteOriginRemote)
166+ agents.originKey = "remote"
167+ agents.request.Remote = true
168+ agents.request.OriginKey = "remote"
169+ agents.request.EnvironmentPolicy = ports.EnvironmentPolicyDaemonOwned
170+
171+ request := ledger.samePeerHandoff(agents.request, ports.AttachTarget{
172+ Session: work.target.SessionName,
173+ Intent: ports.IntentAttach,
174+ ExactTarget: &work.target,
175+ EnvironmentPolicy: ports.EnvironmentPolicyDaemonOwned,
176+ })
177+
178+ require.True(t, request.Remote)
179+ require.Equal(t, ports.RouteOriginRemote, request.Origin)
180+ require.Equal(t, "remote", request.OriginKey)
181+ require.Nil(t, request.RemoteTarget)
182+}
183+
151 func TestRouteAttentionSubscriptionIncludesOnlyActiveOriginRoutes(t *testing.T) {184 func TestRouteAttentionSubscriptionIncludesOnlyActiveOriginRoutes(t *testing.T) {
152 ledger := newRouteLedger()185 ledger := newRouteLedger()
153 first := routeTestCandidate(0, ports.RouteOriginRemote)186 first := routeTestCandidate(0, ports.RouteOriginRemote)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close