The Rail · Reference & analysis

RD.2 TV / cast and watch-party integration

The repository had no Google Cast CAF receiver/sender,

6sections4 minread

On this page

Date: 2026-07-22

Existing-infrastructure audit#

The repository had no Google Cast CAF receiver/sender, react-native-google-cast, AirPlay route picker, or equivalent device-discovery implementation in the OSHUN customer apps. Searches across app dependencies and native/client source found only descriptive casting catalogs in Shakti and low-level DRM/AirPlay capability declarations. Those are not a session transport and were not reused as if they were one.

The reusable authorities that did exist were:

  • RB.5's existing Rail mobile route and Veritas external-broadcast companion;
  • the V10 kernel's single primary VideoLaneArbiter and RingPolicy;
  • Stage's coupled media offer and V4 Match's first-party-live program manifest;
  • RB.3's canonical, tenant/resource-exact LiveMediaTenantLiveChatControl.

RD.2 therefore adds a receiver-grade web TV surface and six-digit phone pairing, without inventing a false native discovery SDK. A TV browser, installed web receiver, or cast receiver URL can open /rail/tv; the existing mobile Rail opens /rail-tv-remote and becomes the remote after pairing.

Contract and policy#

libs/contracts/src/v10/tv-surface.ts owns v10.tv-rail.1 and the pairing and remote-command envelopes. The contract makes these invariants structural:

  • only v3.stage concerts and v4.match-channel esports are party programs;
  • the program ring is exactly games;
  • session/resource ids and six-digit pairing codes are strict;
  • playback is monotonic and revisioned, with bounded position/duration;
  • enabled chat carries one exact tenant/stream room and can exist only for a first-party program;
  • docked-third-party chat is always absent with hg-5-review-required—there is deliberately no legal-review boolean a caller can flip;
  • an unconfigured RB.3 chat organ is also represented honestly as playback-only, never as a working chat affordance.

TvWatchPartyCoordinator is the authoritative in-process state machine. It runs the manifest through RingPolicy.watchPartyChannels before allocating any session or pairing code, tracks distinct paired remotes, authenticates a remote token, deduplicates command ids, rejects stale revisions, and applies only transport capabilities granted by the source. The adult ring is therefore excluded before serialization, not hidden by a client.

RB.3 chat binding#

RailTvWatchPartyChat is a narrow adapter over RB.3's actual LiveMediaTenantLiveChatControl. Join, send, and history calls accept no caller stream id; the adapter derives the tenant and exact stream from the validated TV session. A disabled capability is rejected before resolving or invoking any chat control. V10RailLiveChatControl fixes the Rail tenant over the shared organ, and BFF endpoints expose join/send/history only when that control is configured.

The deployed program authority is all-or-none through OSHUN_V10_RAIL_TV_PROGRAM_URL and OSHUN_V10_RAIL_TV_PROGRAM_TOKEN. Its strict response must echo the authenticated user, requested channel, and program id; malformed, cross-subject, cross-program, or cross-channel responses are rejected. An absent authority returns an honest 503 rather than sample media.

Surfaces#

The TV receiver is a fixed, full-viewport video plane with progressive, HLS, and DASH loading, a restrained lower third, a pairing code, and party-policy status. It polls the authenticated session and reconciles video play/pause and position to the authoritative revision. It does not render a dashboard or chat composer for third-party content.

The existing mobile Rail now exposes a second TV row alongside the Veritas companion. Its remote mode accepts a bounded six-digit code, keeps the remote token separate from V1 auth, polls authoritative state, and sends revisioned play/pause/seek commands. Stale-command failures refresh rather than overwriting the TV state. The design uses one sea-glass accent, cardless divisions, and reduced chrome in accordance with the mandatory frontend guidance.

HG-5#

HG-5 remains open. No legal review occurred in this implementation. The code enforces the pre-review state: third-party playback remains possible, but its chat capability has no room and every attempted bridge operation fails before RB.3 is called. The ledger's human-gate checkbox must stay unchecked until the named review happens.

Verification#

Passing focused checks on 2026-07-22:

  • TV contract: 4 tests;
  • watch-party coordinator: 5 tests;
  • BFF route, deployed program source, and RB.3 bridge: 8 tests;
  • V3 Stage suite after enabling the TV surface: 79 passed, 3 intentionally skipped integration tests;
  • mobile client/surface/navigation: 30 Jest tests;
  • TV receiver: 3 Vitest tests;
  • Chromium Playwright: 2/2, including full-viewport geometry and an axe scan;
  • contract, kernel, focused BFF, and web TypeScript checks;
  • targeted ESLint and Prettier checks;
  • direct production BFF esbuild bundle;
  • Maestro device-matrix dry run and YAML flow wiring.

The full mobile TypeScript command was also run. It reached only five existing, unrelated noUncheckedIndexedAccess errors in libs/contracts/src/study/{evaluation-metrics,performance-environment-matrix}.ts; the RD.2 Jest transform and focused TypeScript-bearing suites are green. Native Maestro execution is unavailable because adb devices is empty and this Linux host has no iOS runtime. A Next production build was not run: on this 15 GiB host the repository's hard gate requires explicit approval for that build. The targeted Next dev Playwright run and web TypeScript check pass. A nominal Nx BFF build was stopped when Nx expanded it to 324 dependency tasks; the exact BFF esbuild production command then passed directly.