mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 00:03:15 +00:00
A phone decides whether a desktop can serve Relay by calling pairing.getEndpoints and pairing.provisionRelay and reading the failure. Both call sites treated only `method_not_found` as "this desktop is too old for Relay, stay on LAN" — and that code is the one answer a genuinely old desktop can never give. runtime-rpc-websocket-dispatch.ts runs the mobile allowlist gate BEFORE the RPC dispatcher. So for a mobile-scoped device `method_not_found` is reachable only for a method that IS allowlisted but unregistered; a method an older desktop predates is absent from both lists and the phone is refused with `forbidden`. The fallback could never fire against the exact desktop it exists for. In pre-profile-pairing-coordinator.ts that is the first-time QR pairing flow, so the failure is not a degraded mode — it throws and the phone ends up with no host profile at all: AssertionError: promise rejected "Error: forbidden: forbidden" instead of resolving ❯ requireSuccess src/transport/pre-profile-pairing-coordinator.ts:288 Both local `isMethodNotFound` predicates are replaced by one shared `isPairingRelayRpcUnavailable` that accepts either code. Safe in both directions: a desktop that serves the probes allowlists them, so `forbidden` on one can only mean "this desktop will not expose Relay pairing to a phone", which is exactly what the caller falls back for. See docs/reference/remote-wire-compatibility.md. The desktop-side test pins the mechanism rather than restating it: a mobile-scoped device gets `forbidden` for an unregistered method while a runtime-scoped peer gets `method_not_found` for the same one. Measured: mobile `vitest run src/transport` 98 files / 723 passed. Mutating away the `forbidden` arm fails both new cases; mutating away the `method_not_found` arm fails both pre-existing cases; mutating the desktop gate to emit `method_not_found` fails the new desktop case. No survivors.