# ECP-0036: Multi-Variant Manifests (One Epoch, Many Variants) Status: Draft Author: Codex Reviewers: founder@every.channel Created: 2026-02-07 ## Decision Extend `ec-core` manifests to optionally carry *multiple* variant hash-lists in a single signed manifest object. One manifest epoch can describe: - the "master" logical stream id (base) - N variants, each with: - variant id - variant stream id - chunk index range - per-chunk hashes - per-variant merkle root Subscribers verify chunks by selecting the variant entry matching the chunk's `stream_id` (derived from encryption `key_id`). ## Motivation - Quality pools (ABR ladders) need coordination: all variants should share epoch boundaries and be verifiable under one signed statement. - One manifest object per epoch reduces gossip/chattiness vs per-variant manifests. - Makes it easy to proxy to playlist-based views (HLS) without coupling the transport to playlists. ## Data Model Add to `ec-core`: - `ManifestVariant` (new) - `variant_id: String` - `stream_id: StreamId` - `chunk_start_index: u64` - `total_chunks: u64` - `merkle_root: String` - `chunk_hashes: Vec` - `metadata: Vec` (variant-specific; optional but useful) Extend `ManifestBody`: - `variants: Option>` Rules: - Legacy manifests keep using `chunk_hashes` (single-variant). - Multi-variant manifests set `chunk_hashes` empty and populate `variants`. - `ManifestBody.merkle_root` becomes: - legacy: merkle root of `chunk_hashes` - multi-variant: merkle root of ordered `variants[].merkle_root` (sorted by `variant_id`) ## Publishing - `ec-node moq-publish` can publish a CMAF ladder: one track per variant, one init track per variant. - After each epoch, publish a single manifest frame containing all variants' hashes for that epoch. ## Subscribing - Subscriber requires manifests as today. - To validate a chunk: - identify `stream_id` from `object.meta.encryption.key_id` (strip `/init` suffix if present) - find a manifest in store that covers `(stream_id, chunk_index)` - compare expected hash from the matching `ManifestVariant`. ## Reversibility - Backwards compatible: old readers ignore `variants`, new readers accept both formats. - If later we move to per-variant manifests, we can keep multi-variant as an optimization.