fix(client-runtime): keep healthy sessions on their current route#25526

closed1
main
maria/takeover-pr-24849
opened3d agobyMmaria
View on GitHubTwo-way sync enabledPR last imported 13h ago

Problem

A successful LAN discovery/auth preflight replaces a healthy session before the new WebSocket opens or synchronizes. If setup fails, the client returns to its old route with a new socket and resyncs unnecessarily.

Change

Keep a healthy session on its current route. Remove speculative route upgrades, their preference/cooldown state, and the now-unused driver preflight API. Necessary reconnects still use the latest ranked routes, including routes learned from the session. Web, desktop, and mobile share this supervisor.

This deliberately trades immediate route optimization for session stability. Maintainer review of that route policy is required.

Scope and approval

This is Maria's requested takeover of the focused bug fix in #24849. Scope is limited to preserving healthy sessions and retaining ranked-route selection for necessary reconnects. Maintainer approval of the shared route-policy change is still required before merge; no prior approval is claimed.

Verification

  • Both opening and synchronization regressions failed on current main (87ea18cad91f) before the fix, then passed.
  • Blacksmith: 111 focused tests passed across supervisor, registry, route selection, and RPC sessions.
  • Blacksmith vp run check:changed: format, lint, knip, seven affected package/dependent typechecks, and 78 changed-file tests passed.
  • A necessary reconnect to the now-working preferred route succeeded and returned authenticated server.getConfig.
  • Chrome with the actual app registry, resolver, driver, RPC session and a second real server behind two loopback proxies: main replaced its working fallback socket after a foreground wakeup (generation 1 -> 2); the fixed branch retained generation 1 with no new socket, through the wakeup and a periodic-check interval. Discovery, auth and tickets were real; the preferred proxy deliberately rejected WebSocket setup.
  • Two independent GPT-6.1-Sol reviewers found no substantive issues on the final head. CodeRabbit generated no actionable comments; Macroscope correctness passed. Approvability requires human review of the route policy.
  • CI passed on the final head: lint, build/typecheck, package tests, browser tests, all eight server shards, and aggregate Check. An unrelated attachment-preview timeout passed on the failed-jobs rerun. Native fingerprint checks also passed.
  • Unverified: physical Tailscale/LAN, packaged Electron, native iOS/Android, hosted relay, and provider turn continuity during a real network transition.

Evidence

before: foreground wakeup interrupts the healthy connection

after: foreground wakeup preserves the healthy connection

before: connected becomes connecting and reconnects

after: connection stays connected

Takeover

Replaces #24849, with thanks to @Zheruel for the original implementation.

The contributor's fork has maintainer edits disabled, so this starts from current main and retains the original implementation, regression cases, and connection policy documentation. No behavior was dropped or moved. The commit preserves the contributor's release credit.

Built with GPT-6.1-Sol in the Codex harness on T3 Code.

Checks

22 successful · 12 skipped · 1 neutral
All checks passed
35753a4

Added 1 commit

  • fix(client-runtime): keep healthy sessions on their current route35753a4
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — This PR changes shared client-runtime connection policy by preventing healthy sessions from being replaced during route discovery, while preserving ranked-route selection for necessary reconnects. Because it changes when socket replacement and resynchronization occur across multiple clients, the policy warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review.

External image Recent review info
External image Run configuration
External image Commits

Reviewing files that changed from the base of the PR and between 87ea18cad91fa246f66e65acd00fe99aa733c14e and 35753a4d77829c80914ac0b0e7f8250851b5108d.

External image Files selected for processing: 5
  • docs/internals/connection-runtime.md
  • packages/client-runtime/src/connection/driver.ts
  • packages/client-runtime/src/connection/registry.test.ts
  • packages/client-runtime/src/connection/supervisor.test.ts
  • packages/client-runtime/src/connection/supervisor.ts
External image Files with no reviewable changes: 1
  • packages/client-runtime/src/connection/registry.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.

Walkthrough

The connection supervisor no longer probes for better routes or switches a healthy session after route discovery. When a reconnect is needed, it uses the current catalog entry, including routes learned during the session.

Changes: Connection route selection

Layer / File(s)Summary
Keep active routes until reconnect
packages/client-runtime/src/connection/driver.ts, packages/client-runtime/src/connection/supervisor.ts, packages/client-runtime/src/connection/registry.test.ts, packages/client-runtime/src/connection/supervisor.test.ts, docs/internals/connection-runtime.md
The driver removes preflight, and the supervisor removes better-route probing, preferred-route state, and route cooldowns. Tests cover keeping a healthy session when a better route fails during opening or synchronization, and using newly reachable or learned routes on a later reconnect. The documentation describes this behavior.

Priority: External image Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Possibly related issues

  • Issue 24516: Describes closing a healthy Tailscale session to attempt LAN, then repeating the fallback; this change removes speculative route upgrades.

Suggested reviewers: juliusmarminge, t3dotgg

Merge Risk: External image Minimal · up to 35753

No identified issue blocks merging. The route policy keeps healthy sessions in place and selects from current routes when reconnection is necessary.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the main change: keeping healthy client-runtime sessions on their current route.
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
Description checkPassedThe description follows the repository template closely. It states the problem, the change, the scope and approval status, and verification results. The Problem section explains that a successful LAN …
Full details: Description check

Explanation

The description follows the repository template closely. It states the problem, the change, the scope and approval status, and verification results. The Problem section explains that a successful LAN discovery/auth preflight replaces a healthy session before the new WebSocket opens or synchronizes, and that setup failure causes an unnecessary return to the old route and resync. The Change section says a healthy session stays on its current route, that speculative upgrades and the driver preflight API are removed, and that necessary reconnects still use the latest ranked routes. The Scope and approval section links the predecessor PR (pulls/24849), states it is a takeover, and says maintainer approval of the shared route-policy change is still required and not claimed. The Verification section lists focused and repo-wide checks with results, browser verification evidence, and unverified areas. Evidence is embedded as before/after screenshots and recordings. Minor gaps: the Scope section does not describe a maintainer approval comment, which the template asks for when approval is claimed. The template also asks for the model and harness used, and the description includes 'Built with GPT-6.1-Sol in the Codex harness on T3 Code.' That line covers it. Overall the description is mostly complete and specific.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

Synced from GitHub

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for 35753a4.

This comment will update automatically after the next completed run.

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

verified as-is at 35753a4d77829c80914ac0b0e7f8250851b5108d on a disposable linux boat vm. no source changes or pushes.

  • installed and ran github/main (c677d5fc45) in /home/user/main, then stopped it before running the exact pr head. ran vp i in both checkouts. only one dev server ran at a time, using isolated .t3 state. actual ports were web 8693 and server 16733.
  • used repository playwright with /usr/bin/google-chrome. paired two addresses through settings, added /home/user/route-qa as a project through the app, and created threads and real codex gpt-6.1-sol turns through the composer. the web client used its hosted-app mode so both saved bearer routes went through the production registry, resolver, driver, authentication, websocket, subscriptions, and orchestration.
  • two transparent local network proxies forwarded to the same real dev server. preferred 18081 answered real discovery/auth/pairing but rejected websocket upgrades; fallback 18082 worked. this injected a transport failure, with no mocked app responses, fixtures, or replay provider.
  • main reproduced the bug during a real 90-second terminal turn: at 09:46:01.406Z it closed the healthy fallback socket, attempted the failing preferred websocket, then opened another fallback socket. settings visibly changed from connected to connecting. the provider turn still completed, so the reproduced defect is unnecessary socket replacement and resynchronization, not loss of the provider process.
  • the pr kept the fallback socket opened at 09:49:23.576Z until an intentional transport drop at 09:51:49.134Z. there were no intermediate websocket closes or preferred websocket attempts across the periodic-check interval and the real 90-second turn. the response was CONTINUITY_OK.
  • after making the preferred route work, the healthy fallback stayed connected. an intentional socket drop reconnected through preferred 18081 at 09:51:52.189Z, while a second real terminal turn was running. that turn returned RECONNECT_OK. a client reload used the saved preferred route, and a new composer turn returned FOLLOWUP_OK.
  • neighboring behavior: switching the environment off disconnected it and removed its projects; switching it on restored the fallback connection and projects. a repeated transport drop then selected the working preferred route, shown in the recording below.
  • blacksmith ran the existing supervisor, registry, route-selection, and rpc-session files: 111 tests passed across 4 files. the github aggregate Check passed; the live rollup has 24 successes, 6 skips, 1 neutral result, and 1 cancelled native-fingerprint run alongside successful runs of that check. no new test files were created.

short transport transcript (utc):

text
1main 09:45:01.148 fallback websocket opens
2main 09:46:01.406 healthy fallback closes without injected loss
3main 09:46:01.529 preferred websocket rejected
4main 09:46:02.700 new fallback websocket opens
5pr 09:49:23.576 fallback websocket opens
6pr [no socket replacement during the 90-second codex turn]
7pr 09:51:49.134 intentional transport drop
8pr 09:51:52.189 preferred websocket opens successfully
9ui CONTINUITY_OK / RECONNECT_OK / FOLLOWUP_OK

before, main unnecessarily reconnects:

main: healthy fallback changes from connected to connecting and back

after, the pr retains the fallback connection beyond the route-check interval:

pr: fallback remains connected while the preferred websocket is unavailable

neighboring behavior, off/on followed by intentional transport loss and recovery on the preferred route:

pr: environment off and on works, then socket loss selects the working preferred route

real provider results after continuity, reconnect, and client reload:

codex gpt-6.1-sol returns continuity, reconnect, and follow-up results in the real client

all captures were inspected. uploaded videos played to completion and seeking worked in t3's browser player.

Not verified

physical lan/tailscale transitions, hosted t3 connect relay and dpop renewal, long native background suspension, packaged electron, macos/windows, and native ios/android were not exercised on this linux vm. the runtime failure injected here was websocket upgrade rejection; the separate initial-config/synchronization failure is covered by the passing existing regression tests, not a real-network run. automatic learned-route insertion was not exercised; these routes were paired and reordered through settings. no claim is made about other providers. maintainer approval of the route policy remains separate from verification.

Note

🤖 Claude Opus 5.5 responding on behalf of Theo

Superseded by #26757, which folds in the route rule: a healthy session keeps its route until the next reconnect. You are credited with a Co-authored-by trailer. Closing this so the two don't conflict.