# ECP-0121: Greedy Multi-Relay Streams Status: Draft ## Problem statement Live streams should be publishable to more than one relay at once so viewers can pick the fastest path and regional relays can mirror each other. The current public directory shape only exposes one `relay_url` per stream, which encourages duplicate publishers when we want redundancy. For OTA sources, duplicate publishers are dangerous because each one opens another tuner read. ## Constraints - Preserve the existing `relay_url`, `broadcast_name`, and `track_name` fields for deployed web, archive, and manual watch links. - Keep those primary fields as the compatibility contract; `relays[]` is additive and optional for consumers. - Do not duplicate HDHomeRun source reads to get multi-region relay presence. - Let the public directory advertise multiple relays before every consumer implements racing. - Keep rollback simple: clients can ignore `relays[]` and keep using the primary legacy fields. ## Decision Add an ordered `relays[]` candidate list to public stream entries and stream upserts. Stream upserts continue to require the primary legacy fields; the first relay is mirrored into those fields and remains the primary/default path. `control-bridge-web` now forwards all relay transports already present in a control announcement instead of flattening to the first relay only. Current consumers can keep reading the legacy fields until they explicitly add relay racing. The intended next step is a single ingest/fanout publisher: read the source once, encode/fragment once, publish the same stream objects to LAX and NYC relay sessions, and optionally let relays mirror to each other. Consumers can then race candidates greedily by availability/latency without causing extra source reads. ## Alternatives considered - Start one publisher per relay. Rejected because it duplicates source reads and can exhaust physical tuners, which was the LA outage failure mode. - Replace the legacy fields with `relays[]`. Rejected because deployed clients and archive workers already depend on the single-relay shape. - Accept `relays[]` without primary legacy fields. Rejected because that would make rollback depend on every publisher being downgraded at the same time as the directory. - Wait for full relay racing before changing the directory. Rejected because exposing the ordered candidate set is a small compatible step that unblocks incremental consumers. ## Rollout / teardown plan Deploy the compatible schema first. Then add publisher fanout and consumer relay racing behind separate flags. Teardown is removing `relays[]` from upserts and consumers; legacy primary-field behavior remains intact throughout.