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
VideoLaneArbiterandRingPolicy; - 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.stageconcerts andv4.match-channelesports 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-partychat is always absent withhg-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.