Skip to content

fix(client): T3 Connect clients reconnect once a new tunnel is ready - #16554

Merged
shivamhwp merged 2 commits into
mainfrom
fix/connect-retries-unready-tunnel
Oct 13, 2026
Merged

shivamhwp merged 2 commits into
mainfrom
fix/connect-retries-unready-tunnel

Conversation

@shivamhwp

@shivamhwp shivamhwp commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

A T3 Connect client that tried to connect while its host was setting up a new tunnel showed "Connection failed" and never tried again on its own. It only retried when you switched tabs, the network changed, or you pressed Reconnect, even after the tunnel was up.

While a host replaces its tunnel, the relay keeps the allocation marked not ready until the new tunnel and DNS record exist (recordTunnel clears readyAt, markReady sets it, in infra/relay/src/environments/ManagedEndpointAllocations.ts). A connect request in that window gets environment_connect_not_authorized with reason managed_endpoint_allocation_not_ready. The client mapped every environment_connect_not_authorized to a blocked permission error, and the supervisor never retries a blocked error on a timer. Nothing on the client changes when the tunnel becomes ready, so the client stayed parked.

That one reason now maps to a transient endpoint-unavailable error, so the client retries with the normal backoff. Every other not-authorized reason (endpoint_provider_not_managed, a missing link, a mismatch, a missing reason from an older relay) stays blocked. The status text now says "The environment's T3 Connect tunnel is still being set up." instead of "Relay rejected the environment connection request (managed_endpoint_allocation_not_ready)."

This is a small fix for an obvious bug under the contributing guide: a temporary relay state was treated as permanent, and the change only affects that one reason.

Testing

What you see

I can't make the hosted relay return this answer on demand, and running T3 Connect needs a real sign-in. So I built the real web app with a small test-only patch (not part of this PR) that makes the next 4 connection attempts fail with exactly the relay's managed_endpoint_allocation_not_ready answer, passed through the real mapManagedRelayError. Everything after that is the real app. I paired a browser, turned the simulation on, restarted the server to force a reconnect, and recorded the chat view. The same patch ran on main 5e22256 and on main 5e22256 with this PR merged.

Before (main) After (this PR)
Banner "corex-t3 is offline" with a Reconnect button "corex-t3 is reconnecting"
Retries on its own No. 1 attempt in 95 seconds Yes, through all 4 "not ready" answers
Back online Never, until you click Reconnect 44 seconds after the drop, no clicks
Before: 54 s after the drop After: 24 s, retrying After: 94 s, connected

Recordings at 3x (the overlay clock and socket log are real time):

Before After

Full MP4s: before, after.

Tests

The rest uses the real error mapping and the real EnvironmentSupervisor with a fake driver and TestClock.

New test in errors.test.ts: managed_endpoint_allocation_not_ready maps to a transient endpoint-unavailable error with the new message. endpoint_provider_not_managed and a missing reason still map to blocked permission. On main it fails:

× retries a tunnel that is still being set up, and blocks other refusals
AssertionError: expected ConnectionBlockedError: Relay rejected th… to match object

With the fix, vp test run src/connection/errors.test.ts src/relay/errorPresentation.test.ts src/connection/supervisor.test.ts in packages/client-runtime passes 70 of 70.

A temporary supervisor test, not committed, sent the relay error through mapManagedRelayError for the first 3 attempts and then let the 4th succeed, with no wakeup:

Before (main) After
First failure blocked, permission backoff, endpoint-unavailable
After 30 simulated minutes still blocked, 1 attempt connected after 15 simulated seconds, 4 attempts
endpoint_provider_not_managed blocked, 1 attempt in 30 min blocked, 1 attempt in 30 min (unchanged)

The "Before" column comes from a separate check run on main 29366ea: after the first relay refusal, it advances the clock 30 minutes and asserts the connection is still blocked with exactly 1 attempt, for both reasons. A tab switch or similar wakeup was the only thing that reconnected it.

Relay discovery runs the same mapping for the environment list. It shows any mapped failure as an error on that row, so there it only changes the message.

tsc --noEmit in packages/client-runtime passes. Lint on the changed files has no findings.

Not tested: a live T3 Connect host swapping its tunnel, and the mobile app. The recording uses the simulated relay answer described above.

🤖 Generated with Claude Code (Claude Opus 5.5)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Oct 6, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 6, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at dbf3920

Macroscope's review found this PR approvable — This is a narrowly scoped client bug fix that reclassifies one documented, temporary tunnel-readiness response as retryable while preserving blocked handling for other refusals. The existing exponential backoff is reused, and focused tests cover both the new behavior and unchanged cases.

Notes:

  • Diff unchanged. Approvability was decided on eligibility alone.

No code changes detected at 286c9c6. Prior analysis still applies.

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

@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 6, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review October 6, 2026 18:58

Dismissing prior approval to re-evaluate dbf3920

@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 20.9 KiB 20.9 KiB 0 B (0.0%) 29.3 KiB ✅
Codex Live turn messages 2 2 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.2 KiB 21.2 KiB 0 B (0.0%) 29.3 KiB ✅
Claude Live turn messages 2 2 0 (0.0%) 8 ✅

Baseline: df26ef9 · PR result: 286c9c6 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e09652bf-e5c1-46a4-a4e6-23625324fa87
📥 Commits

Reviewing files that changed from the base of the PR and between dbf3920 and 286c9c6.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9a6f5cd7-206a-48ad-8cdb-736ea95d2f08
📥 Commits

Reviewing files that changed from the base of the PR and between 29366ea and dbf3920.

📒 Files selected for processing (3)
  • packages/client-runtime/src/connection/errors.test.ts
  • packages/client-runtime/src/connection/errors.ts
  • packages/client-runtime/src/relay/errorPresentation.ts

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

📝 Walkthrough

The client runtime now maps managed endpoint allocation-not-ready refusals to a transient endpoint-unavailable error and displays a tunnel-setup message. Tests cover this case and other connect refusal reasons.

Changes: Managed endpoint connect refusals

Layer / File(s) Summary
Map and present connect refusals
packages/client-runtime/src/connection/errors.ts, packages/client-runtime/src/relay/errorPresentation.ts, packages/client-runtime/src/connection/errors.test.ts
The error mapper treats managed_endpoint_allocation_not_ready as a transient endpoint-unavailable error. The presentation logic displays a tunnel-setup message. Tests cover this reason, an unmanaged provider, and a missing reason.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to dbf39

No actionable issue remains that would prevent merging after normal checks.

Security architecture risk: 🔵 Low · up to dbf39

The change enables backed-off retries during tunnel setup without relaxing permission or identity checks. No authorization bypass was identified. Live tunnel-replacement recovery and aggregate retry load were not verified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The added activity is repeated connect requests from clients waiting on unready allocations. Per attempt, the allocation lookup remains scoped to the authenticated user's ID and the requested environment ID; the change does not grant access to another user's allocation. Aggregate request load can increase across waiting clients, but was not measured.

Trust Boundaries and Controls

  • observed — Every connect request still requires the environment:connect scope, agreement between the requested and principal proof-key thumbprints, and a DPoP check bound to the access token. The client also checks the returned environment ID and current cloud-session identity. Authentication failures and non-readiness refusal reasons remain blocked.

Resilience and Maintainability Implications

  • observed — Retries use the existing exponential jittered delay with a five-minute ceiling, not an immediate retry loop. The number of retries is not bounded while a connection remains desired and eligible. A persistently unready allocation therefore continues to fail with backoff; disconnect, interruption, and scoped cleanup remain available.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the primary change: clients reconnect after a T3 Connect tunnel becomes ready.
Description check ✅ Passed The description explains the problem, implementation, scope rationale, testing evidence, limitations, and agent usage. It does not use the template's exact "Change," "Scope and approval," and "Verific…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@shivamhwp
shivamhwp merged commit a143fa3 into main Oct 13, 2026
29 checks passed
@shivamhwp
shivamhwp deleted the fix/connect-retries-unready-tunnel branch October 13, 2026 02:42
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Oct 13, 2026
## What's Changed
* fix(server): apply confirmed Claude subagent outcomes by @Yash-Singh1 in pingdotgg/t3code#18778
* fix(mobile): Browser page no longer logs a duplicate key warning by @tris203 in pingdotgg/t3code#18776
* fix(web): a numeric q in the pull requests URL no longer crashes the page by @ScottN-PV in pingdotgg/t3code#18666
* fix(client): T3 Connect clients reconnect once a new tunnel is ready by @shivamhwp in pingdotgg/t3code#16554
* fix(web): leaving the home page while the app loads no longer bounces you to a new draft by @shivamhwp in pingdotgg/t3code#18672
* fix(mobile): attachment images no longer re-download on every reconnect by @shivamhwp in pingdotgg/t3code#18824
* fix(server): a migration id clash stops startup with a clear error instead of crash-looping by @shivamhwp in pingdotgg/t3code#15925
* fix(server): a thread with an event type from a newer build can still resync after a downgrade by @shivamhwp in pingdotgg/t3code#15937
* fix(server): Codex titles and branch names no longer start the user's MCP servers by @brycedbjork in pingdotgg/t3code#17058
* fix(server): Claude thinking before a tool call stays a collapsed Thought by @maria-rcks in pingdotgg/t3code#18887
* perf(server): cached branch PR lookups no longer start git processes by @SunkenInTime in pingdotgg/t3code#17063
* fix(web): compact merge buttons show when they need a second click by @TonybynMp4 in pingdotgg/t3code#18878
* fix(mobile): pull requests load from another environment when theirs is offline by @juliusmarminge in pingdotgg/t3code#18698
* perf(web): collect active tool calls without array shifts by @saphid in pingdotgg/t3code#18853
* fix(web): center the pace icon on the limit card's "left" label by @akash3444 in pingdotgg/t3code#18580
* fix(web): update everything includes npm-installed servers again by @ScottN-PV in pingdotgg/t3code#18709
* fix(server): review guides find Bitbucket heads reported by short hash by @ahilles107 in pingdotgg/t3code#18900
* fix(web): scheduled task model picker no longer shifts the dialog by @flamboh in pingdotgg/t3code#18940
* fix(ci): CodeRabbit reviews no longer request changes by @Yash-Singh1 in pingdotgg/t3code#18954

## New Contributors
* @brycedbjork made their first contribution in pingdotgg/t3code#17058

**Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261013.3042...v0.0.46-nightly.20261013.3053

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261013.3053
github-actions Bot added a commit to davidvanderklay/t3code-flake that referenced this pull request Oct 13, 2026
## What's Changed
* fix(server): apply confirmed Claude subagent outcomes by @Yash-Singh1 in pingdotgg/t3code#18778
* fix(mobile): Browser page no longer logs a duplicate key warning by @tris203 in pingdotgg/t3code#18776
* fix(web): a numeric q in the pull requests URL no longer crashes the page by @ScottN-PV in pingdotgg/t3code#18666
* fix(client): T3 Connect clients reconnect once a new tunnel is ready by @shivamhwp in pingdotgg/t3code#16554
* fix(web): leaving the home page while the app loads no longer bounces you to a new draft by @shivamhwp in pingdotgg/t3code#18672
* fix(mobile): attachment images no longer re-download on every reconnect by @shivamhwp in pingdotgg/t3code#18824
* fix(server): a migration id clash stops startup with a clear error instead of crash-looping by @shivamhwp in pingdotgg/t3code#15925
* fix(server): a thread with an event type from a newer build can still resync after a downgrade by @shivamhwp in pingdotgg/t3code#15937
* fix(server): Codex titles and branch names no longer start the user's MCP servers by @brycedbjork in pingdotgg/t3code#17058
* fix(server): Claude thinking before a tool call stays a collapsed Thought by @maria-rcks in pingdotgg/t3code#18887
* perf(server): cached branch PR lookups no longer start git processes by @SunkenInTime in pingdotgg/t3code#17063
* fix(web): compact merge buttons show when they need a second click by @TonybynMp4 in pingdotgg/t3code#18878
* fix(mobile): pull requests load from another environment when theirs is offline by @juliusmarminge in pingdotgg/t3code#18698
* perf(web): collect active tool calls without array shifts by @saphid in pingdotgg/t3code#18853
* fix(web): center the pace icon on the limit card's "left" label by @akash3444 in pingdotgg/t3code#18580
* fix(web): update everything includes npm-installed servers again by @ScottN-PV in pingdotgg/t3code#18709
* fix(server): review guides find Bitbucket heads reported by short hash by @ahilles107 in pingdotgg/t3code#18900
* fix(web): scheduled task model picker no longer shifts the dialog by @flamboh in pingdotgg/t3code#18940
* fix(ci): CodeRabbit reviews no longer request changes by @Yash-Singh1 in pingdotgg/t3code#18954

## New Contributors
* @brycedbjork made their first contribution in pingdotgg/t3code#17058

**Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261013.3042...v0.0.46-nightly.20261013.3053

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261013.3053
adampeterhiggins added a commit to adampeterhiggins/t3code that referenced this pull request Oct 13, 2026
* fix(gitlab): merge request details report their head commit (pingdotgg#18608)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(server): rename built-in models from settings (pingdotgg#18840)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): Git actions follow the selected thread (pingdotgg#18862)

* fix(desktop): preserve updater failure causes in diagnostics (pingdotgg#18864)

* fix(web): attach dropped threads to pending answers (pingdotgg#18789)

* fix(web): keep button text stable during press scaling (pingdotgg#18866)

* fix(bitbucket): preserve PR head commits for review guides (pingdotgg#18402)

* fix(server): return null for unresolved optional commands (pingdotgg#18871)

* fix: show computer-use action titles and align app icons (pingdotgg#18865)

* fix(server): apply confirmed Claude subagent outcomes (pingdotgg#18778)

* fix(mobile): Browser page no longer logs a duplicate key warning (pingdotgg#18776)

* fix(web): a numeric q in the pull requests URL no longer crashes the page (pingdotgg#18666)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(client): T3 Connect clients reconnect once a new tunnel is ready (pingdotgg#16554)

Co-authored-by: PR Batch Tester <agent@local.test>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(web): leaving the home page while the app loads no longer bounces you to a new draft (pingdotgg#18672)

Co-authored-by: PR Batch Tester <agent@local.test>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(mobile): attachment images no longer re-download on every reconnect (pingdotgg#18824)

Co-authored-by: PR Batch Tester <agent@local.test>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(server): a migration id clash stops startup with a clear error instead of crash-looping (pingdotgg#15925)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: PR Batch Tester <agent@local.test>

* fix(server): a thread with an event type from a newer build can still resync after a downgrade (pingdotgg#15937)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: PR Batch Tester <agent@local.test>

* fix(server): Codex titles and branch names no longer start the user's MCP servers (pingdotgg#17058)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Yash Singh <saiansh2525@gmail.com>

* fix(server): Claude thinking before a tool call stays a collapsed Thought (pingdotgg#18887)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

* perf(server): cached branch PR lookups no longer start git processes (pingdotgg#17063)

* fix(web): compact merge buttons show when they need a second click (pingdotgg#18878)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(mobile): pull requests load from another environment when theirs is offline (pingdotgg#18698)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* perf(web): collect active tool calls without array shifts (pingdotgg#18853)

Co-authored-by: SAPHID <saphid@users.noreply.github.com>
Co-authored-by: GPT-6.1 Sol <noreply@openai.com>

* fix(web): center the pace icon on the limit card's "left" label (pingdotgg#18580)

* fix(web): update everything includes npm-installed servers again (pingdotgg#18709)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(server): review guides find Bitbucket heads reported by short hash (pingdotgg#18900)

Co-authored-by: Pawel Mikolajczuk <pmikolajczuk@atlassian.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): scheduled task model picker no longer shifts the dialog (pingdotgg#18940)

* fix(ci): CodeRabbit reviews no longer request changes (pingdotgg#18954)

---------

Co-authored-by: Scott Norteman <snorteman@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Theo Browne <me@t3.gg>
Co-authored-by: Yash Singh <saiansh2525@gmail.com>
Co-authored-by: Paweł Mikołajczuk <pawel@mikolajczuk.in>
Co-authored-by: Tristan Knight <admin@snappeh.com>
Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com>
Co-authored-by: PR Batch Tester <agent@local.test>
Co-authored-by: Bryce Bjork <brycedbjork@gmail.com>
Co-authored-by: maria <maria@kuuro.net>
Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>
Co-authored-by: Dara Adedeji <76637177+SunkenInTime@users.noreply.github.com>
Co-authored-by: Antony <97451137+TonybynMp4@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: Alex Southwell <saphid@gmail.com>
Co-authored-by: SAPHID <saphid@users.noreply.github.com>
Co-authored-by: GPT-6.1 Sol <noreply@openai.com>
Co-authored-by: Akash Moradiya <64416825+akash3444@users.noreply.github.com>
Co-authored-by: Pawel Mikolajczuk <pmikolajczuk@atlassian.com>
Co-authored-by: oliver <97427849+flamboh@users.noreply.github.com>
simonli357 pushed a commit to simonli357/t3code that referenced this pull request Oct 13, 2026
…ingdotgg#16554)

Co-authored-by: PR Batch Tester <agent@local.test>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit a143fa3)
vMobxAi pushed a commit to ItzJsimp/leonidas-code that referenced this pull request Oct 14, 2026
…ingdotgg#16554)

Co-authored-by: PR Batch Tester <agent@local.test>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit a143fa3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants