Skip to content

fix(web): a browser connects as soon as pairing succeeds - #16553

Closed
shivamhwp wants to merge 1 commit into
mainfrom
fix/web-pairing-connects-now
Closed

shivamhwp wants to merge 1 commit into
mainfrom
fix/web-pairing-connects-now

Conversation

@shivamhwp

@shivamhwp shivamhwp commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

If a browser sat on the pair page for a while before you pasted a pairing token, the app said "Still connecting" for up to 3 minutes after you clicked Continue. Pairing had worked. The app was waiting out a retry timer.

While a browser is unpaired, the server rejects its WebSocket, so the connection keeps retrying with a delay that doubles each time. Nothing told the connection that pairing had succeeded, so it waited for the next scheduled try. After pairing, the pair page now asks the primary environment to retry right away, the same as the Reconnect button does.

This is a small fix for an obvious bug under the contributing guide: the bug comes from one missing call after a successful pairing, and the change adds that call on the success path only.

Testing

I ran a production web build (vp build) served by node apps/server/src/bin.ts --mode web against a fresh base dir. Playwright drove headless Chromium: open /pair with no session, wait, mint a token with t3 pair, paste it, click Continue, then measure when the app's /ws socket opens. An overlay in the page shows real time and the last socket events.

Time on /pair before pasting Before (main 78552a8) After
2 min socket opened 55s after Continue 0.11s
3 min 3m08s 0.14s
4 min 3m00s 0.14s

Screenshots 6 seconds after Continue: all three runs on main show "Still connecting", and all three with the fix show the app.

Before: 6s after Continue After: 6s after Continue

Recordings of the 3-minute run, at 6x (the overlay clock is real time):

Before After

Full MP4s: before, after.

Other cases, run with the fix:

  • A pairing link that submits on load connected in 0.9s, the same as main (0.7s). The retry delay hasn't grown on a fresh load.
  • An invalid token and an already used token both show "Invalid pairing token" and stay on /pair. The retry only runs after a successful pairing, so neither starts an extra socket.
  • Mobile and the hosted app pair through registerPairing, not this page, so they're unchanged. Desktop authenticates the primary with a bearer and doesn't show this page.

The retry itself is the existing retryNow, covered by "explicit retry interrupts the current backoff" and "explicit retry starts a fresh backoff sequence" in supervisor.test.ts. I didn't add a component test. It would only assert that the callback is wired.

tsc --noEmit in apps/web passes. Lint on the changed file has no new findings.

🤖 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

macroscopeapp Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The change is a focused fix that triggers the existing primary connection retry immediately after pairing succeeds. Because it modifies an authentication-directory file, the sensitive-code review requirement calls for human review.

Notes:

  • Diff unchanged. Approvability was decided on eligibility alone.

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

@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: 9503155 · PR result: ec71f4d · 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.

@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 6, 2026
@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

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: 2c601b31-f425-4c26-9baa-1ef626b099a9
📥 Commits

Reviewing files that changed from the base of the PR and between 9503155 and ec71f4d.

📒 Files selected for processing (1)
  • apps/web/src/components/auth/PairingRouteSurface.tsx

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


📝 Walkthrough

Walkthrough

After credential submission succeeds, PairingRouteSurface retries the primary environment when its ID is available, then calls onAuthenticated in a transition. Failed submissions still set an error and return before these actions.

Changes

Pairing authentication

Layer / File(s) Summary
Retry the primary environment after authentication
apps/web/src/components/auth/PairingRouteSurface.tsx
The component reads the primary environment ID and obtains a retryNow command. After successful submission, it retries the environment when the ID is available, then calls onAuthenticated in a transition.

Priority: ➖ Normal

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

Change: Bug fix

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to ec71f

Successful pairing retries the connection with an established session before navigation. No material merge risk remains.

Security Architecture Review

Security architecture risk: ⚪ Minimal · up to ec71f

The change requests an earlier connection attempt only after pairing succeeds. It reuses the existing primary-environment retry mechanism without changing credentials, permissions or server authorization. No material security risk was found in the changed flow.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The additional action is bounded to the browser client's registered primary environment. The changed caller does not derive an endpoint or environment ID from the pairing credential, enumerate secondary environments or grant additional session privileges.

Trust Boundaries and Controls

  • observed — Attacker-supplied pairing input still passes through credential exchange and authenticated-session verification before reaching the new retry call. Rejected credentials cannot reach that call through the changed success path, and subsequent WebSocket attempts remain independently authenticated by the server.

Resilience and Maintainability Implications

  • observed — Disabling retry failure reporting changes warning behavior, not retry execution or authorization. Command results settle through the existing wrapper, so the fire-and-forget call does not make successful pairing depend on retry completion.
🚥 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 summarizes the main change: the browser connects immediately after pairing succeeds.
Description check ✅ Passed The description explains the problem and fix, justifies the focused scope, and reports specific verification results. It also includes screenshots and recordings for the UI behavior.
✨ 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

Copy link
Copy Markdown
Collaborator Author

Closing this. #9785 already fixes the same bug on main: after pairing succeeds, the pair page now reloads the whole page, and a fresh page starts a fresh connection with no leftover retry timer.

I retested on main 30cc788 with a production web build in headless Chromium. A tab that sat on /pair for 3 minutes connected 0.48s after Continue without this PR, and 0.52s with it. Re-pairing a connected browser and invalid or reused tokens behaved the same with and without the PR. The retry call this PR adds now fires just before that reload and has no effect.

@shivamhwp shivamhwp closed this Oct 8, 2026
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