Skip to content

feat(android): production-ready Watch Together (PR 108 slice F) - #117

Merged
RXWatcher merged 13 commits into
mainfrom
split/108-f-watch-together
Jul 27, 2026
Merged

feat(android): production-ready Watch Together (PR 108 slice F)#117
RXWatcher merged 13 commits into
mainfrom
split/108-f-watch-together

Conversation

@RXWatcher

@RXWatcher RXWatcher commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Stack

Scope

  • Production-safe Watch Together WebSocket reconnect semantics, immutable room/auth leases, exact physical-socket transport authorization, and application-scoped room ownership.
  • Reachable phone/TV host, join, lobby, playback, voting, suggestion, policy, replacement, and close flows.
  • Reconnect-safe attach/readiness/transport delivery, stale completion rejection, historical suggestion hydration, and external MediaSession/player authority reconciliation.
  • Privacy hardening for auth snapshots and socket request rendering. The server V3 contract still requires room/profile credentials in the WebSocket query; the redundant access JWT is omitted and app logs/request string rendering redact credentials.
  • Rational frame-rate decoding needed by the production catalog fixture.

Live two-participant validation

Validated against local Silo API protocol V3 with distinct Host E2E and Guest E2E identities on:

  • Silo_TV (emulator-5554)
  • Silo_Phone (emulator-5556)

Covered create/join/handshake, attach ordering, host play/pause/seek, guest host-only rejection, guest-play-pause policy, host override, suggestions/voting/promotion, drift/buffering convergence, hard transport interruption and reconnect/rejoin, background/foreground, room/session replacement, host departure, and terminal room close.

The final on-device correction made the TV close confirmation a focusable popup with root-wide initial-focus tracking. D-pad Down remained on Keep watching without focus steal; Cancel preserved both participants; Close returned the host to detail and ejected the guest. Final phone/TV log scans found zero query-credential URLs, bearer tokens, JWT-shaped values, or raw auth snapshots.

No physical Shield device was touched.

Review corrections

Independent lifecycle/concurrency/security review drove test-first fixes for:

  • immutable room lease/generation races and late REST/socket completions;
  • exact captured socket authorization across replacement and policy changes;
  • non-blocking reset while transport I/O is blocked;
  • single-flight external player reconciliation and TV lifecycle restoration;
  • TV close-dialog modal focus ownership.

Final independent verdict: Ready: Yes; no remaining correctness, privacy/security, concurrency, or lifecycle blockers.

Verification

  • ./scripts/test-check-build-supply-chain.sh
  • ./scripts/check-build-supply-chain.sh
  • ./gradlew --no-daemon testDebugUnitTest :androidApp:assembleDebug :androidTvApp:assembleDebug --max-workers=1 --rerun-tasks — 175/175 tasks executed, pass
  • ./gradlew --no-daemon :androidTvApp:testDebugUnitTest :androidTvApp:assembleDebug --max-workers=1 --rerun-tasks — 105/105 tasks executed, pass
  • Final focused TvWatchTogetherSurfaceSourceTest + TV APK assembly — pass
  • Two-emulator live matrix above
  • git diff --check

Traceability

The design, source mapping, and dependency order are in docs/superpowers/plans/2026-07-27-pr108-slice-f-watch-together.md.

PR #108 source intent mapped into this stack includes:

  • feature entry: 9fe27a27
  • transport/send/open corrections: 323510a2, c6ba32ef, e171e011
  • lobby/invite/TV focus: acfac18a, fca6d7c6, bc58049b
  • voting and empty vote rooms: ea5756ec, 8f36f7d2, 923a1a7f
  • browsing suggestions: 530f9488, f91aa62e
  • application-scoped ownership intent: 864de27e, 79b4278d

The forward split preserves those behavioral contracts as a net vertical diff while the local commit sequence records the corrected architecture and review rounds.

Slice G resolution

The planned final TV/catalog slice requires no additional stacked PR:

All three commits are ancestors of this head, and attempted cherry-picks were empty. Focused MixedLibraryModeTest, TvRequestPresentationTest, and *TvPlayer* verification passed. The local unpushed split/108-g-tv-catalog branch and restacked traceability commit 5dc9455a are retained as the archival G resolution; no docs-only G PR was created. Its content and stable patch ID are identical to the pre-restack commit b653253f.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@RXWatcher, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 57 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 414d319d-a680-4f71-b4f0-62928f744767

📥 Commits

Reviewing files that changed from the base of the PR and between 14dab30 and e62c694.

📒 Files selected for processing (71)
  • .superpowers/sdd/2026-07-27-pr108-slice-f-watch-together/task-1-report.md
  • android-shared/src/androidMain/kotlin/org/siloserver/silo/common/player/PlayWhenReadyReconciliation.kt
  • android-shared/src/androidMain/kotlin/org/siloserver/silo/common/player/PlaybackSessionLifecycle.kt
  • android-shared/src/androidUnitTest/kotlin/org/siloserver/silo/common/network/WatchTogetherRealtimeWebSocketTest.kt
  • android-shared/src/androidUnitTest/kotlin/org/siloserver/silo/common/player/PlayWhenReadyReconciliationTest.kt
  • android-shared/src/androidUnitTest/kotlin/org/siloserver/silo/common/player/PlaybackSessionLifecycleTest.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/di/AndroidModule.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/ui/screens/detail/ItemDetailScreen.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/ui/screens/detail/MovieDetailContent.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/ui/screens/detail/SeriesDetailContent.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/ui/screens/player/PlayerScreen.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/ui/screens/player/RoomSyncController.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/ui/screens/watchtogether/SuggestToRoomViewModel.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/ui/screens/watchtogether/WatchTogetherEntrySheet.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/ui/screens/watchtogether/WatchTogetherEntryViewModel.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/ui/screens/watchtogether/WatchTogetherLobbyScreen.kt
  • androidApp/src/androidMain/kotlin/org/siloserver/silo/android/ui/screens/watchtogether/WatchTogetherLobbyViewModel.kt
  • androidApp/src/androidUnitTest/kotlin/org/siloserver/silo/android/ui/screens/watchtogether/LobbyAutoNavigateTest.kt
  • androidApp/src/androidUnitTest/kotlin/org/siloserver/silo/android/ui/screens/watchtogether/SuggestToRoomSurfaceSourceTest.kt
  • androidApp/src/androidUnitTest/kotlin/org/siloserver/silo/android/ui/screens/watchtogether/WatchTogetherEntryDestinationTest.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/di/AndroidTvModule.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/navigation/TvAppNavigation.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/auth/QrCodePanel.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/detail/TvItemDetailScreen.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/player/TvPlayerScreen.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/player/TvRoomSyncController.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/player/TvVideoPlaybackStarter.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/watchtogether/TvJoinCodeDialog.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/watchtogether/TvSuggestToRoomViewModel.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/watchtogether/TvWatchTogetherEntryDialog.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/watchtogether/TvWatchTogetherLobbyScreen.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/watchtogether/TvWatchTogetherLobbyViewModel.kt
  • androidTvApp/src/androidMain/kotlin/org/siloserver/silo/tv/ui/screens/watchtogether/TvWatchTogetherViewModel.kt
  • androidTvApp/src/androidUnitTest/kotlin/org/siloserver/silo/tv/pip/TvPictureInPictureSourceTest.kt
  • androidTvApp/src/androidUnitTest/kotlin/org/siloserver/silo/tv/ui/screens/player/TvPlaybackFreshLoadOwnershipTest.kt
  • androidTvApp/src/androidUnitTest/kotlin/org/siloserver/silo/tv/ui/screens/watchtogether/LobbyNavigationDecisionTest.kt
  • androidTvApp/src/androidUnitTest/kotlin/org/siloserver/silo/tv/ui/screens/watchtogether/TvWatchTogetherSurfaceSourceTest.kt
  • docs/superpowers/plans/2026-07-27-pr108-slice-f-watch-together.md
  • docs/superpowers/specs/2026-07-27-pr108-slice-f-watch-together-design.md
  • shared/src/commonMain/kotlin/org/siloserver/silo/di/RepositoryModule.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/model/catalog/CatalogModels.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/model/catalog/FrameRateSerializer.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/model/feature/ClientSurfacePolicy.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/network/AuthInterceptorImpl.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/network/AuthScopeSnapshot.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/network/CleartextOriginConsent.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/network/HttpOriginPolicy.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/network/IdentityTransitionBarrier.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/network/PlaybackRealtimeClient.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/network/WatchTogetherRealtimeClient.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/network/WatchTogetherRealtimeEvent.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/network/api/WatchTogetherApi.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/repository/WatchTogetherRepository.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/watchtogether/RoomDeliveryLatch.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/watchtogether/RoomEntryUiPolicy.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/watchtogether/RoomSession.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/watchtogether/RoomTransportAuthority.kt
  • shared/src/commonMain/kotlin/org/siloserver/silo/watchtogether/RoomVote.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/model/catalog/CatalogTrackSerializationTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/model/feature/ClientSurfacePolicyTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/network/HttpOriginPolicyTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/network/IdentityTransitionBarrierTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/network/SiloAuthPluginPinTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/network/WatchTogetherRealtimeClientTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/network/api/WatchTogetherApiTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/repository/WatchTogetherRepositoryTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/watchtogether/RoomDeliveryLatchTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/watchtogether/RoomEntryUiPolicyTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/watchtogether/RoomSessionTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/watchtogether/RoomTransportAuthorityTest.kt
  • shared/src/commonTest/kotlin/org/siloserver/silo/watchtogether/RoomVoteTest.kt
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch split/108-f-watch-together

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.

@RXWatcher
RXWatcher force-pushed the split/108-f-watch-together branch from 36d92db to 5f01d26 Compare July 27, 2026 15:36
@RXWatcher
RXWatcher force-pushed the split/108-f-watch-together branch from 5f01d26 to e62c694 Compare July 27, 2026 15:55
Base automatically changed from split/108-e-subtitles to main July 27, 2026 16:40
@RXWatcher
RXWatcher marked this pull request as ready for review July 27, 2026 16:41
@RXWatcher
RXWatcher merged commit 57d6126 into main Jul 27, 2026
2 checks passed
@RXWatcher
RXWatcher deleted the split/108-f-watch-together branch July 27, 2026 16:41
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