Skip to content

Fix native pairing sign-in failures - #6457

Merged
azooz2003-bit merged 30 commits into
mainfrom
task-connect-device-auth-hang
Jun 21, 2026
Merged

azooz2003-bit merged 30 commits into
mainfrom
task-connect-device-auth-hang

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jun 19, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Record display-safe failures on hosted browser sign-in callbacks, including invalid callback payloads, state mismatches, callback validation failures, and abandoned attempts.
  • Update the Connect iPhone/iPad window so sign-in-in-progress shows a dedicated Connecting state, slow sign-in exposes the default-browser fallback, and failed callbacks return to the signed-out prompt with the concrete error instead of leaving the user on a spinner.
  • Add regression coverage for tagged debug auth URL origin/scheme generation and native callback rejection/validation failures.

Diagnosis

  • Auth did not always complete. When the browser returned callback tokens that failed native validation, or returned an invalid/mismatched callback, the app rejected the callback but did not keep a user-visible failure for the pairing window.
  • The web handler intentionally allows production cmux/cmux-nightly schemes, local cmux-dev, and local cmux-dev-* only when the local dev server env allowlists the exact tagged scheme. Tagged macOS builds already generate the matching local origin and cmux-dev- callback scheme; this PR codifies that with an app test instead of weakening the allowlist.

Testing

  • swift test --package-path Packages/Shared/CmuxAuthRuntime --filter HostBrowserSignInFlowTests
  • xcodebuild -project cmux.xcodeproj -scheme cmux-unit -configuration Debug -destination 'platform=macOS' -derivedDataPath /tmp/cmux-pairau test -only-testing:cmuxTests/AuthEnvironmentTests
  • python3 -m json.tool Resources/Localizable.xcstrings >/dev/null
  • rg -n '"auth.error.invalid_callback"|"mobile.pairing.signIn.connecting"|Text("[A-Z][^"]+"|Button("[A-Z][^"]+"' Resources/Localizable.xcstrings Sources/Mobile/Pairing/MobilePairingView.swift Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthError.swift

Localization

  • Added English and Japanese strings for auth.error.invalid_callback and mobile.pairing.signIn.connecting.
  • Reused existing localized account sign-in fallback copy for the slow browser fallback.

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Fixes native pairing sign‑in failures by classifying browser session outcomes, surfacing safe errors in the UI, and adding a reliable “Connecting…” flow with a default‑browser fallback. Adds HostBrowserAuthSessionResult, new AuthError cases, localized messages (including a generic browser sign‑in failure), and stronger guards around external callbacks and state.

  • Bug Fixes

    • Classify ASWebAuthenticationSession completions into HostBrowserAuthSessionResult (.callback/.cancelled/.failed), mapping OS/network/start errors; treat external callbacks during an active attempt as a cancellation.
    • Record display‑safe failures as lastFailure (.invalidCallback, .browserSignInFailed(_), .timedOut); clear on new attempts, success, or sign‑out.
    • Reject invalid payloads, state mismatches, and stateful external callbacks without an active attempt as .invalidCallback; map unsafe validation errors to .serverError(0, "auth_failed").
    • Preserve fallback callback state across retries until success; ignore stale callbacks after sign‑out; bound test waits and simplify the deadline helper.
    • Add regression tests for OS session classification (cancel/presentation failures), invalid/mismatched callbacks, unauthorized validation, timeout/cancellation, stale callbacks after sign‑out, fallback retry, and a tagged debug sign‑in URL using local origin and cmux-dev-<tag>.
  • New Features

    • Show lastFailure on the signed‑out prompt; add a Connecting state with a slow‑sign‑in hint and an “Open in Browser” fallback that reuses the active attempt’s state.
    • Introduce AuthError.invalidCallback and AuthError.browserSignInFailed(_) with generic, localized UI messages on macOS/iOS.

Written for commit 8245509. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Show the latest hosted browser sign-in failure details on the signed-out screen.
    • During active hosted sign-in, display “Connecting…” and, when slow, a slow-sign-in fallback with an “Open in Browser” action.
  • Bug Fixes
    • Strengthened hosted sign-in callback validation and consistently records appropriate failure reasons, including timeouts.
  • Localization
    • Added localized copy for invalid sign-in callbacks and connecting/slow-sign-in UI.
  • Tests
    • Expanded and refactored hosted-browser sign-in flow test coverage, including new failure scenarios and a localhost debug sign-in URL test.

@vercel

vercel Bot commented Jun 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 21, 2026 4:13am
cmux-staging Building Building Preview, Comment Jun 21, 2026 4:13am

@coderabbitai

coderabbitai Bot commented Jun 19, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a lastFailure: AuthError? observable property to HostBrowserSignInFlow, populated across the sign-in lifecycle (timeout, invalid callback, completion errors, cleared on sign-out/new attempt). Introduces an invalidCallback AuthError case with localization. Extracts callback-state parsing into a new helpers file. Updates MobilePairingView to show failure descriptions and a slow-sign-in fallback UI. Adds comprehensive test infrastructure and failure test cases with full migration of existing tests.

Changes

Auth Failure State Tracking and Pairing UI

Layer / File(s) Summary
AuthError.invalidCallback case and localization
Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthError.swift, Resources/Localizable.xcstrings
Adds the invalidCallback enum case with documentation and localized errorDescription, plus auth.error.invalid_callback and mobile.pairing.signIn.connecting strings across multiple locales.
lastFailure property and lifecycle integration
Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserSignInFlow.swift
Declares public private(set) var lastFailure: AuthError?; clears it on signOut() and new attempt start; sets it to .timedOut on timeout, .invalidCallback on routing/state-mismatch failures, and to the display-safe error on callback completion throws (skipped for .cancelled); replaces local callback-state helpers with global ones.
Callback state extraction and logging helpers
Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserSignInFlowHelpers.swift
Introduces @MainActor ResumeOnceFlag for once-resume semantics; adds authCallbackState(from:) to extract query state, redactedAuthState(_:) for prefix-only representation, and authCallbackSummary(_:) for compact URL summaries.
MobilePairingView failure display and slow-sign-in fallback
Sources/Mobile/Pairing/MobilePairingView.swift
Routes .loading through a new loadingContent view that shows "Connecting…" when signing in (plus slowSignInFallback with an "Open in Browser" button when slow); the signed-out screen conditionally renders the last failure description in orange.
HostBrowserSignInFlow test harness and helpers
Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HostBrowserSignInFlowTestSupport.swift
Introduces HostBrowserSignInFlowHarness and makeHostBrowserSignInFlowHarness(...) factory; provides hostBrowserCallbackURL(...) and hostBrowserFallbackCallbackURL() builders, state extraction from session URLs, and async main-actor waiting helpers (waitForHostBrowserSession, waitForHostBrowserCondition).
New HostBrowserSignInFlow failure test cases
Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HostBrowserSignInFlowFailureTests.swift
Adds four test cases covering invalid callback payloads, state mismatches, token validation failures, and timeout scenarios; each asserts the appropriate lastFailure value and expected flow behavior.
Existing test migration to host-browser helpers
Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HostBrowserSignInFlowTests.swift
Updates all existing test cases to use makeHostBrowserSignInFlowHarness, waitForHostBrowserSession, and host-browser-specific callback URL helpers instead of generic factories, ensuring consistent session and callback handling across all scenarios.
Tagged debug AuthEnvironment.signInURL test
cmuxTests/AuthEnvironmentTests.swift
Adds a test verifying localhost-based HTTP sign-in URL construction with configured port and validates nested return/callback URLs use the correct schemes (cmux-dev-pair-auth) and hosts (auth-callback).

Sequence Diagram(s)

sequenceDiagram
  participant MobilePairingView
  participant HostBrowserSignInFlow
  participant HostBrowserSession
  participant Callback Handler
  
  MobilePairingView->>HostBrowserSignInFlow: startAttempt()
  Note over HostBrowserSignInFlow: lastFailure = nil, isSigningIn = true
  HostBrowserSignInFlow->>HostBrowserSession: creates browser session
  
  alt Callback state mismatch
    Callback Handler->>HostBrowserSignInFlow: handleCallbackURL(mismatched state)
    HostBrowserSignInFlow->>HostBrowserSignInFlow: lastFailure = .invalidCallback
    HostBrowserSignInFlow->>MobilePairingView: publish lastFailure change
    MobilePairingView->>MobilePairingView: show orange error caption
  else Timeout
    HostBrowserSignInFlow->>HostBrowserSignInFlow: browserAttemptTimeout fires
    HostBrowserSignInFlow->>HostBrowserSignInFlow: lastFailure = .timedOut
    HostBrowserSignInFlow->>HostBrowserSession: cancel session
  else Slow signing in
    MobilePairingView->>MobilePairingView: signInIsSlow = true
    MobilePairingView->>MobilePairingView: show slowSignInFallback
    MobilePairingView->>HostBrowserSignInFlow: openBrowserFallback(activeAttemptSignInURL)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

  • manaflow-ai/cmux#5728: Introduced AuthError display-safe enum cases (including .timedOut) and the auth.error.timed_out localization key that this PR's lastFailure mechanism depends on.
  • manaflow-ai/cmux#5776: Both PRs modify HostBrowserSignInFlow.swift's callback completion path around completeCallback, with #5776 adjusting external sign-in token-clearing behavior while this PR adds lastFailure/invalidCallback recording and state-mismatch handling.
  • manaflow-ai/cmux#6113: Introduces signInIsSlow and activeAttemptSignInURL to HostBrowserSignInFlow for the slow-sign-in fallback UI that this PR wires into MobilePairingView.

Poem

🐇 A little rabbit hops through the sign-in gate,
When callbacks go wrong, lastFailure won't wait!
.timedOut, .invalidCallback — orange text appears,
"Open in Browser" soothes those slow-connect fears.
With helpers extracted and tests all in place,
The pairing UI shines with a warm, helpful grace! 🌟

🚥 Pre-merge checks | ✅ 22 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (22 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix native pairing sign-in failures' directly captures the primary objective of addressing unhandled sign-in callback failures and improving error visibility in the pairing UI.
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.
Cmux Swift Actor Isolation ✅ Passed All production code maintains proper Swift 6 actor isolation: @MainActor-isolated classes (HostBrowserSignInFlow, ResumeOnceFlag), Sendable value types (AuthError), pure helpers undecorated, and Sw...
Cmux Swift Blocking Runtime ✅ Passed PR introduces no blocking/timing synchronization in production code. Task.sleep found only in pre-existing code and deterministic test scaffolding (allowed cases).
Cmux Expensive Synchronous Load ✅ Passed PR adds no expensive synchronous loaders to main actor/interactive paths. All changes involve lightweight enum assignments, property access, URL parsing, and NSWorkspace.shared.open() for launching...
Cmux Cache Substitution Correctness ✅ Passed The PR adds 'lastFailure: AuthError?' as a transient, non-persisted UI hint property in HostBrowserSignInFlow, not a cache substitution. It is cleared on new attempts and sign-out, stored only in m...
Cmux No Hacky Sleeps ✅ Passed The custom check "cmux no hacky sleeps" applies only to TypeScript, JavaScript, shell, and non-Swift build/runtime scripts. All files modified in this PR are Swift source code (.swift) or localizat...
Cmux Algorithmic Complexity ✅ Passed PR introduces no algorithmic complexity violations. Collection operations (first(where:), map) in HostBrowserSignInFlowHelpers operate on URL query parameters (max 5-10 items), explicitly allowed a...
Cmux Swift Concurrency ✅ Passed No legacy async patterns detected. PR uses properly managed Task instances (stored for lifecycle), SwiftUI/XCTest boundaries, and async/await throughout. No DispatchQueue, Combine, or completion-ha...
Cmux Swift @Concurrent ✅ Passed All async functions in the PR either inherit @MainActor isolation (HostBrowserSignInFlow methods) or are explicitly @MainActor-annotated (test helpers). No missing @concurrent on nonisolated async...
Cmux Swift File And Package Boundaries ✅ Passed All Swift files comply with boundaries: no oversized new files, <250 lines added to existing files, focused responsibilities (auth flow, error types, UI), domain logic in CmuxAuthRuntime package, U...
Cmux Swiftpm Lockfiles ✅ Passed PR includes both package-local (CmuxAuthRuntime) and root Xcode Package.resolved files; cmux-owned .gitignore files don't ignore Package.resolved; no new external dependencies added without lockfil...
Cmux Swift Logging ✅ Passed No violations of swift-logging.md: no print/NSLog/dump/debugPrint in production code; all logging uses AuthDebugLog with unified logging system and automatic redaction of secrets.
Cmux User-Facing Error Privacy ✅ Passed All new user-facing error and status messages follow privacy guidelines: generic language ("The sign-in callback was invalid. Try signing in again.", "Connecting…") with no vendor names, internal p...
Cmux Full Internationalization ✅ Passed All new user-facing Swift text uses String(localized:defaultValue:) API. Both new string catalog entries (auth.error.invalid_callback, mobile.pairing.signIn.connecting) include translated values fo...
Cmux Swiftui State Layout ✅ Passed SwiftUI state patterns in MobilePairingView comply with rules: HostBrowserSignInFlow and MobilePairingModel use modern @Observable pattern; no new @StateObject/@published; ForEach only over value t...
Cmux Architecture Rethink ✅ Passed PR implements a small, well-scoped correctness fix by adding lastFailure property to HostBrowserSignInFlow with clear ownership and single source of truth. Uses required continuation infrastructure...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR modifies only MobilePairingView (a SwiftUI View component within an existing window), not window creation code. MobilePairingWindowController with identifier "cmux.mobilePairingWindow" already r...
Cmux Source Artifacts ✅ Passed All 9 changed files are legitimate hand-written source code, tests, test fixtures, and localization catalogs with no prohibited artifacts, temp directories, build output, or generated logs.
Cmux No Test Or Debug Seam In Production Source ✅ Passed No test or debug seams in production source. The lastFailure property is a legitimate observable feature displayed in the production UI; helper functions in HostBrowserSignInFlowHelpers.swift sup...
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the key aspects outlined in the template including summary, diagnosis, testing approach, and localization details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task-connect-device-auth-hang

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Jun 19, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes native pairing sign-in failures by replacing the opaque URL? completion type with a typed HostBrowserAuthSessionResult enum (.callback, .cancelled, .failed), adding a lastFailure: AuthError? observable property to surface display-safe errors in the Connect iPhone/iPad window, and improving the pairing view with a dedicated "Connecting…" state and a slow-browser fallback.

  • Core logic: ASWebBrowserAuthSessionFactory now classifies every ASWebAuthenticationSession completion into a typed result, and HostBrowserSignInFlow propagates that result through generation-guarded paths into lastFailure, clearing it on new attempts, sign-out, and success.
  • UI: MobilePairingView gains a loadingContent path that shows "Connecting…" when isSigningIn is true and a "Open in Browser" fallback when signInIsSlow fires; errors appear on the signed-out prompt instead of leaving the user on a spinner.
  • i18n: All new string keys ship with all 20 catalog locales on macOS and with en/ja on iOS (matching the iOS catalog's existing locale set).

Confidence Score: 5/5

Safe to merge. The failure classification, lastFailure propagation, and generation guards are all correct; i18n is complete across every supported locale.

The typed result enum replaces a stringly-absent URL?, every lastFailure write is guarded by the existing sign-out generation check, the AsyncStream-based deadline helper is race-free under cooperative MainActor scheduling, and the previous thread's generation-guard fix is present in the catch branch. New regression tests cover all the introduced failure paths.

No files require special attention.

Important Files Changed

Filename Overview
Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserSignInFlow.swift Central flow refactored to use typed HostBrowserAuthSessionResult; lastFailure written with sign-out generation guards in all paths including the new catch branch; awaitWithDeadline replaced with a clean AsyncStream-based implementation; no actor isolation issues.
Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/ASWebBrowserAuthSessionFactory.swift Completion bridge now calls sessionResult(callbackURL:error:) to map OS error codes to typed results; nonisolated helper correctly avoids actor contention for the classification logic.
Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserAuthSessionResult.swift New Equatable, Sendable enum replacing URL? throughout the flow; clean, minimal API.
Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthError.swift Two new cases (invalidCallback, browserSignInFailed) added with generic, user-safe localized descriptions; internal diagnostic reason string is not exposed in errorDescription.
Sources/Mobile/Pairing/MobilePairingView.swift Splits loadingContent into sign-in-in-progress (Connecting + slow fallback) vs. generic spinner; observes lastFailure for the signed-out prompt; all new strings routed through String(localized:defaultValue:).
Resources/Localizable.xcstrings Five new keys added each with all 20 catalog locales.
ios/cmux/Resources/Localizable.xcstrings Adds auth.error.browser_sign_in_failed and auth.error.invalid_callback with en/ja, matching the iOS catalog's existing two-locale set.
Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HostBrowserSignInFlowFailureTests.swift New test file covering invalid callback payload, state mismatch, validation errors, sign-out race, start failure, browser session failure, and timeout.
cmuxTests/AuthEnvironmentTests.swift New taggedDebugSignInURLUsesLocalOriginAndTagCallbackScheme test validates tagged debug builds produce a localhost origin and cmux-dev- callback scheme.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as MobilePairingView
    participant Flow as HostBrowserSignInFlow
    participant Factory as ASWebBrowserAuthSessionFactory
    participant OS as ASWebAuthenticationSession
    participant Coord as AuthCoordinator

    UI->>Flow: beginSignIn() / signIn(timeout:)
    Flow->>Flow: "lastFailure = nil"
    Flow->>Factory: makeSession(signInURL:callbackScheme:)
    Factory->>OS: session.start()
    OS-->>Factory: completion(URL?, Error?) [off-main]
    Factory->>Factory: sessionResult(callbackURL:error:)
    Note over Factory: Maps to .callback / .cancelled / .failed
    Factory-->>Flow: "@MainActor (HostBrowserAuthSessionResult)"

    alt .callback(url)
        Flow->>Coord: completeExternalSignIn()
        Coord-->>Flow: success
        Flow->>Flow: "lastFailure = nil"
        Flow-->>UI: "isSigningIn = false (authenticated)"
    else .cancelled
        Flow-->>UI: "isSigningIn = false (no failure recorded)"
    else .failed(reason)
        Flow->>Flow: "lastFailure = .browserSignInFailed(reason)"
        Flow-->>UI: "isSigningIn = false"
        UI->>UI: show lastFailure in signedOut prompt
    end

    alt External callback URL arrives
        UI->>Flow: handleCallbackURL(url)
        alt state matches active attempt
            Flow->>Coord: completeExternalSignIn()
            Flow->>Flow: "lastFailure = nil"
        else state mismatch
            Flow->>Flow: "lastFailure = .invalidCallback"
        end
    end

    alt Attempt timeout fires
        Flow->>Flow: "lastFailure = .timedOut"
        Flow->>Flow: cancelActiveAttempt()
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as MobilePairingView
    participant Flow as HostBrowserSignInFlow
    participant Factory as ASWebBrowserAuthSessionFactory
    participant OS as ASWebAuthenticationSession
    participant Coord as AuthCoordinator

    UI->>Flow: beginSignIn() / signIn(timeout:)
    Flow->>Flow: "lastFailure = nil"
    Flow->>Factory: makeSession(signInURL:callbackScheme:)
    Factory->>OS: session.start()
    OS-->>Factory: completion(URL?, Error?) [off-main]
    Factory->>Factory: sessionResult(callbackURL:error:)
    Note over Factory: Maps to .callback / .cancelled / .failed
    Factory-->>Flow: "@MainActor (HostBrowserAuthSessionResult)"

    alt .callback(url)
        Flow->>Coord: completeExternalSignIn()
        Coord-->>Flow: success
        Flow->>Flow: "lastFailure = nil"
        Flow-->>UI: "isSigningIn = false (authenticated)"
    else .cancelled
        Flow-->>UI: "isSigningIn = false (no failure recorded)"
    else .failed(reason)
        Flow->>Flow: "lastFailure = .browserSignInFailed(reason)"
        Flow-->>UI: "isSigningIn = false"
        UI->>UI: show lastFailure in signedOut prompt
    end

    alt External callback URL arrives
        UI->>Flow: handleCallbackURL(url)
        alt state matches active attempt
            Flow->>Coord: completeExternalSignIn()
            Flow->>Flow: "lastFailure = nil"
        else state mismatch
            Flow->>Flow: "lastFailure = .invalidCallback"
        end
    end

    alt Attempt timeout fires
        Flow->>Flow: "lastFailure = .timedOut"
        Flow->>Flow: cancelActiveAttempt()
    end
Loading

Reviews (13): Last reviewed commit: "Localize browser sign-in failure message" | Re-trigger Greptile

Comment thread Resources/Localizable.xcstrings

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Resources/Localizable.xcstrings`:
- Around line 19406-19439: Remove the incorrect CLI surface error keys
(cli.claude-hook.error.invalidSurface and cli.claude-hook.error.surfaceNotFound)
from the localization strings file. Instead, add the two required keys that are
actually referenced in the code: auth.error.invalid_callback (needed by
AuthError.swift for the invalidCallback case) and
mobile.pairing.signIn.connecting (needed by MobilePairingView for the connecting
state). Each key must include both English (en) and Japanese (ja) translations
with appropriate string values for their respective use cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ca2af455-1aba-4a88-a9a3-57efefa90be7

📥 Commits

Reviewing files that changed from the base of the PR and between 13e4654 and 4d323fc.

📒 Files selected for processing (1)
  • Resources/Localizable.xcstrings

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Resources/Localizable.xcstrings`:
- Around line 19406-19439: Remove the incorrect CLI surface error keys
(cli.claude-hook.error.invalidSurface and cli.claude-hook.error.surfaceNotFound)
from the localization strings file. Instead, add the two required keys that are
actually referenced in the code: auth.error.invalid_callback (needed by
AuthError.swift for the invalidCallback case) and
mobile.pairing.signIn.connecting (needed by MobilePairingView for the connecting
state). Each key must include both English (en) and Japanese (ja) translations
with appropriate string values for their respective use cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ca2af455-1aba-4a88-a9a3-57efefa90be7

📥 Commits

Reviewing files that changed from the base of the PR and between 13e4654 and 4d323fc.

📒 Files selected for processing (1)
  • Resources/Localizable.xcstrings
🛑 Comments failed to post (1)
Resources/Localizable.xcstrings (1)

19406-19439: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical inconsistency: Wrong localization keys added.

The PR objectives, AI summary, and code snippets (AuthError.swift, HostBrowserSignInFlow.swift) all indicate this layer should add:

  • auth.error.invalid_callback (for AuthError.invalidCallback case)
  • mobile.pairing.signIn.connecting (for MobilePairingView connecting state)

Instead, this diff adds unrelated CLI surface error keys:

  • cli.claude-hook.error.invalidSurface
  • cli.claude-hook.error.surfaceNotFound

AuthError.swift expects "auth.error.invalid_callback" to exist (see context snippet 1, line 62), but it's not present in this diff. This will cause runtime localization failures when the auth error is displayed.

Please verify the correct diff was provided, or add the expected auth.error.invalid_callback and mobile.pairing.signIn.connecting keys with en+ja translations. Based on learnings, only en and ja locales are required for new keys.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Resources/Localizable.xcstrings` around lines 19406 - 19439, Remove the
incorrect CLI surface error keys (cli.claude-hook.error.invalidSurface and
cli.claude-hook.error.surfaceNotFound) from the localization strings file.
Instead, add the two required keys that are actually referenced in the code:
auth.error.invalid_callback (needed by AuthError.swift for the invalidCallback
case) and mobile.pairing.signIn.connecting (needed by MobilePairingView for the
connecting state). Each key must include both English (en) and Japanese (ja)
translations with appropriate string values for their respective use cases.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserSignInFlow.swift (1)

165-170: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Only consume fallback state after the callback succeeds.

Line 169 clears pendingFallbackCallbackState before completeCallback validates the payload and publishes the session. If that completion fails transiently, the issued fallback state is burned and a retry of the same browser callback is rejected. Also clear lastFailure on success so a prior rejected callback in the same attempt does not leave stale failure UI state.

Proposed fix
         if callbackRouter.isAuthCallbackURL(url),
            let state = authCallbackState(from: url),
            state == pendingFallbackCallbackState {
             log.log("auth.callback.external.routeToIssuedFallback")
-            pendingFallbackCallbackState = nil
             return await completeCallback(url: url, attemptID: nil, acceptedExternalState: state)
         }
@@
         if authCallbackState(from: url) == pendingFallbackCallbackState {
             pendingFallbackCallbackState = nil
         }
+        lastFailure = nil
         return true

Also applies to: 464-467

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserSignInFlow.swift`
around lines 165 - 170, The pendingFallbackCallbackState is being cleared before
completeCallback validates and succeeds, which causes the state to be consumed
even if the callback completion fails transiently. Move the statement that sets
pendingFallbackCallbackState to nil to only execute after completeCallback
succeeds. Additionally, clear lastFailure when the callback completes
successfully to prevent stale failure UI state from persisting after a prior
rejected callback in the same attempt. Apply this same fix pattern to the
similar callback handling code also mentioned in the review (the other location
around lines 464-467).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HostBrowserSignInFlowTestSupport.swift`:
- Around line 71-85: The waitForHostBrowserSession and
waitForHostBrowserCondition functions use unbounded while loops that can cause
tests to hang indefinitely if conditions never become true. Add an explicit
deadline or timeout to both functions by tracking elapsed time or using a
deadline API, and throw a clear timeout error when the deadline is exceeded
instead of continuing to poll indefinitely. This ensures tests fail fast with
meaningful error messages rather than hanging.

---

Outside diff comments:
In
`@Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserSignInFlow.swift`:
- Around line 165-170: The pendingFallbackCallbackState is being cleared before
completeCallback validates and succeeds, which causes the state to be consumed
even if the callback completion fails transiently. Move the statement that sets
pendingFallbackCallbackState to nil to only execute after completeCallback
succeeds. Additionally, clear lastFailure when the callback completes
successfully to prevent stale failure UI state from persisting after a prior
rejected callback in the same attempt. Apply this same fix pattern to the
similar callback handling code also mentioned in the review (the other location
around lines 464-467).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 952f6c29-b3ce-4b1c-a57a-31975737e91b

📥 Commits

Reviewing files that changed from the base of the PR and between 4d323fc and ade58d7.

📒 Files selected for processing (5)
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserSignInFlow.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserSignInFlowHelpers.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HostBrowserSignInFlowFailureTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HostBrowserSignInFlowTestSupport.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HostBrowserSignInFlowTests.swift

…uth-hang

# Conflicts:
#	.github/swift-file-length-budget.tsv
@azooz2003-bit
azooz2003-bit force-pushed the task-connect-device-auth-hang branch from dc6e941 to d544669 Compare June 20, 2026 03:46
@azooz2003-bit
azooz2003-bit merged commit 263eeb4 into main Jun 21, 2026
36 checks passed

This branch was successfully deployed

1 active deployment
Preview – cmux — 8245509f Deployed Jun 21, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant