stablyai / stablyai/orca

mobile: relay pairing recovery strands on "recovery pending" after desktop rotates QR

Open
#14,005 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
71.3k
Forks
4.7k
Avg merge
14h 54m
Merged PRs (30d)
520

Description

## Describe the bug

When a mobile pairing attempt fails after the E2EE handshake but before provisioning completes, the desktop-generated pairing journal is left in AsyncStorage with `winner` set. If the user then regenerates the QR on the desktop (which the desktop responds to by revoking the previous device's relay binding via `queueRelayDeviceRevoke`), every credential the journal holds becomes permanently invalid. The next phone scan is blocked by `saveMobileRelayPairingJournal`'s guard with the error `"mobile relay pairing recovery pending"`, and the journal never clears until `inviteExpiresAt + 10min grace` elapses (~20 minutes from the original QR mint).

## Reproduction

1. Desktop Orca → Settings → Mobile → generate QR (mode: Anywhere)
2. Phone scans QR; relay path is unreachable (e.g. phone not yet on VPN, desktop control socket RST'd)
3. The phone gets far enough to set `winner` on the journal, then fails at `pairing.provisionRelay`
4. Desktop regenerates the QR (or the user toggles connection mode) — `runtime-rpc.ts:807-816` revokes the previous device's relay binding
5. Phone scans the new QR — `saveMobileRelayPairingJournal` throws `"mobile relay pairing recovery pending"`
6. Force-quit + relaunch the phone app: `recoverMobileRelayPairing` runs, but the cell returns `4401 BAD_OUTER_CREDENTIAL` for every credential and the catch block at `mobile-relay-pairing-recovery.ts:144` swallows it as if it were a transient transport error → returns `'deferred'` → journal stays → next scan still blocked

## Expected behavior

Recovery should abandon the journal as soon as every credential is authoritatively rejected (`4401`), so a fresh scan can proceed immediately instead of waiting the full invite TTL + grace window.

## Environment

- Orca mobile app
- Orca desktop main @ recent
- Pairing mode: Anywhere (relay)
- Observed in a network environment where the relay cell is intermittently reachable from the phone

## Diagnosis

`mobile/src/transport/mobile-relay-pairing-recovery.ts:144` `catch {}` treats every error the same. It should distinguish `RelayOuterError(BAD_OUTER_CREDENTIAL)` from transient failures and abandon when all credentials are permanent.

Contributor guide

Open the contributing guide

Research direction

Start in mobile/src/transport/mobile-relay-pairing-recovery.ts around line 144 and trace recoverMobileRelayPairing's handling of RelayOuterError(BAD_OUTER_CREDENTIAL), alongside the revocation flow in runtime-rpc.ts:807-816. Verify that all authoritative credential rejections abandon the journal while transient failures remain deferred, allowing a fresh scan immediately.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
mobile, security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.