# ECP-0004: global stream identifiers and swarms

Status: Draft

## Problem

We need a global, deterministic way to identify streams so that identical broadcasts from different antennas can converge in the same swarm without coordination.

## Decision

Adopt a two-layer identifier scheme:

1. **Broadcast identity**: a logical identifier derived from broadcast metadata (PSIP/ATSC) such as transport stream ID and program number. This is the primary convergence key.
2. **Source identity**: a physical identifier used when broadcast identity is not yet available (e.g., early ingestion). This is a fallback.

A canonical stream ID string will be generated as:

`ec/stream/v1/<scope>/<fields...>/profile-<profile>/variant-<variant>`

Where `<scope>` is `broadcast` or `source`.

### Broadcast scope fields

- `standard` (e.g., `atsc`)
- `tsid-<transport_stream_id>` (when known)
- `program-<program_number>` (when known)
- optional `callsign-<callsign>` and `region-<region>` as hints

### Source scope fields

- `kind` (e.g., `hdhr` or `linux-dvb`)
- `device-<device_id>` when available
- `channel-<channel_reference>` when available

### Profile and variant

- `profile` identifies the deterministic encoding profile.
- `variant` identifies audio language, resolution, or alternate tracks.

## Consequences

- The network can converge on the same stream even when multiple relays ingest the same broadcast.
- Early ingestion may start with `source` scope and migrate to `broadcast` scope once PSIP metadata is parsed.

## Alternatives considered

- Single opaque UUID per stream: rejected because it prevents convergence without coordination.
- Content hash as stream ID: deferred; may be layered later as an availability primitive.

## Rollout / teardown

- Implement `StreamKey` in `ec-core`.
- Extend ingest pipeline to parse PSIP/ATSC IDs and promote `source` to `broadcast` IDs.
- Revise once PSIP parsing is in place.
