feat(remote): recognize servers across addresses and fix SiloRemote routing - #342
Merged
Merged
Conversation
…outing Consume the server identity contract (Silo-Server/silo-server#1271) so a phone on a network-plugin address and a TV on the public address recognize one deployment, and fix a cluster of SiloRemote playback bugs found while testing it. Identity (#341): - Registry entries learn a verified deployment identity; matching accepts equal identities alongside the existing origin rule. Registry keys and credential slots are unchanged. - SiloControl hello, TXT record, and handoff offer carry the identity and the deployment's other addresses. The TV probes candidates and uses the first that answers with the expected identity; a different identity is refused. - Companion pairing pushes identity and endpoints. The TV probes the pushed address, and on failure shows provider help with an explicit public fallback. Frames echo the pushed URL; the TV saves the address that worked. Failures now carry typed codes. SiloRemote routing and playback: - One "engaged" predicate drives the mode button, mini-bar, and routing. - Every streaming play goes through the router, so an engaged TV (including mid-reconnect) always takes it; offline plays prompt. - Playing a different title asks before replacing what the TV is showing. - The phone accepts a reused handoff_ready without a challenge, and the TV hands the identity generation to a replacing player. - The remote scrubber commits on value settle, so a missed end-of-edit callback no longer pins the slider and swallows later drags. - Connecting to a server from the Change Server flow pops the stack. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
Quick104 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (31)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
This was referenced Sep 22, 2026
Quick104
added a commit
that referenced
this pull request
Sep 23, 2026
The API v2 and diagnostics contract fixtures are now pinned to server commit `84ed9e596`. The sync script only vendors from an explicit ref, so anyone re-running it at that ref gets the same bytes. This PR also splits `ContentView.body` so Xcode 26.3 can type-check it. The iOS job of the Apple regression workflow had failed on main since #342 with "unable to type-check this expression in reasonable time". Behavior is unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A phone signed in through a network-plugin address (Tailscale) and an Apple TV signed in at the public address are the same server, but the clients derive server identity from the URL, so the remote-only picker hides the TV and a profile handoff forces the TV onto the phone's address even when it cannot reach it. Companion setup has the same reachability gap and reports every failure as
auth_failed.Testing the fix on shared-dev surfaced several pre-existing SiloRemote bugs: playback sometimes started on the phone while a TV was engaged, sending a second title to a TV failed, and the remote's scrubber intermittently did nothing.
Closes #341. Server contract: Silo-Server/silo-server#1271 (deployed to shared-dev). Sibling: Silo-Server/silo-android#352.
Solution
Identity across addresses
ServerEntrygains an optionalverifiedServerIdlearned fromGET /api/v2/system/identitywhen a server is added, on foreground refresh, and when pairing persists. Registry keys and credential slots are unchanged.ServerRegistry.serversMatchaccepts equal identities alongside the existing origin rule.hello, andhandoff_offercarryserverIdentity, and the offer carriesserverEndpointsfromGET /api/v2/system/connections. Protocol version stays 2; older peers ignore the keys. The TV probes its own saved address, the phone's, then public and provider endpoints, and uses the first that answers with the expected identity. An address answering with another identity is refused (identity_mismatch); none reachable yieldsserver_unreachablewith provider help.pushServercarriesserverIdentityandendpoints(protocol stays v1). The TV probes the pushed address and, when unreachable, shows help naming the provider from its manifest display name with an explicit "Use " choice. Nothing switches without the user.deviceStartedandserverResultalways echo the pushed URL; the TV saves the address that worked.serverResult.erroris now one ofauth_failed,denied,expired,unreachable,identity_mismatch, and the phone summarises it.SiloRemote routing and playback
SiloControlClient.remotePlaybackEngagedis the single "TV engaged" predicate (true through reconnect, false during a silent auto-resume probe). The mode button, mini-bar, and routing all read it.AppRouter.presentPlayerroutes every streaming play through an interceptor installed by the root view, so an engaged TV takes the request and the local player never opens. This covers the home rail play badge, deep links, and the stale "Try Anyway" alerts without per-site checks. A play during reconnect waits for the link instead of falling through. Offline plays prompt for phone or TV. PiP restore is skipped while a TV is engaged.handoff_readywith no challenge (previously every second title timed out), and the TV hands the temporary identity generation to a replacing player instead of ending it mid-load.Validation
AccountSessionPersistenceTestsfails on this simulator with keychain error -34018 both with and without this change; confirmed on a clean baseline checkout.Risks and follow-up
AI disclosure
claude-fable-5-1🤖 Generated with Claude Code
Summary by CodeRabbit