diff --git a/docs/backlog/24-access-streaming-v2.md b/docs/backlog/24-access-streaming-v2.md index ac67f17..556fccd 100644 --- a/docs/backlog/24-access-streaming-v2.md +++ b/docs/backlog/24-access-streaming-v2.md @@ -124,11 +124,19 @@ P3 first vertical slice delivered (`agent/audio-v2-p3`): - DAV2 Range reads now use bounded gateway requests, hedge the header and first chunk against a second gateway when the first one stalls, and cache the winning gateway per CID for the browser session. +- MSE playback now prepares the current chunk plus two future chunks while the + current clear chunk is appended. Appends stay strictly ordered, track changes + abort the bounded pipeline, and at most three container chunks are in the + preparation window (about 1.5 MiB at the current 512 KiB default). +- The browser imports the AES content key once per playback instead of once per + chunk. Known chunk ranges must return the exact byte count; truncated or + mismatched `206` responses retry another gateway instead of being + misclassified as a content-authentication failure. - The resolver emits `dotify:dav2-startup` events for key authorization, gateway selection, header readiness, first range, first decrypt, first append, fallback, and error phases. -- Remaining #88 work: worker-based decryption, chunk read-ahead/pipelining, - first-chunk sizing experiments, the browser/device validation matrix, and the +- Remaining #88 work: worker-based decryption, first-chunk sizing experiments, + the browser/device validation matrix, startup telemetry export, and the backend read-through gateway decision. Product SDK replanning note (2026-07-14): diff --git a/docs/backlog/README.md b/docs/backlog/README.md index d3f3710..5bd92c7 100644 --- a/docs/backlog/README.md +++ b/docs/backlog/README.md @@ -87,7 +87,7 @@ Deferred (needs a backend channel, deliberately not faked): persisted room mood. | Backlog doc | Status | Goal | | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `24-access-streaming-v2.md` | P1/P2 delivered; P3 first vertical slice delivered with DAV2 refs, playback fallback, and startup metrics (design in `docs/design/dotify-v2-access-and-streaming.md`) | Remove the 42% preview; three-mode artist policy (free / paid / human-free via Proof of Personhood); sign-once session auth for key delivery; encrypted chunked streaming (`dotify.audio.v2`) for fast starts; Product SDK / Playground / Humanity feasibility as a later host-integration track | +| `24-access-streaming-v2.md` | P1/P2 delivered; P3 DAV2 vertical slice and bounded read-ahead delivered; real-browser/gateway validation remains (design in `docs/design/dotify-v2-access-and-streaming.md`) | Remove the 42% preview; three-mode artist policy (free / paid / human-free via Proof of Personhood); sign-once session auth for key delivery; encrypted chunked streaming (`dotify.audio.v2`) for fast starts; Product SDK / Playground / Humanity feasibility as a later host-integration track | Ticket 24 supersedes the preview-based rows above: the 42% doctrine and the ticket 18 preview assets are consciously retired by access model v2. diff --git a/docs/design/dotify-v2-access-and-streaming.md b/docs/design/dotify-v2-access-and-streaming.md index 7c86652..19bb0ab 100644 --- a/docs/design/dotify-v2-access-and-streaming.md +++ b/docs/design/dotify-v2-access-and-streaming.md @@ -1,6 +1,6 @@ # Dotify v2 - access, protected streaming, and Polkadot App alignment -Status: living design and delivery plan. Last reviewed: 2026-07-10. +Status: living design and delivery plan. Last reviewed: 2026-07-18. This document is the source of truth for the Dotify v2 access and streaming pivot. It should answer four questions: @@ -32,9 +32,11 @@ Dotify v2 changes the production spine in three ways: The current implementation now includes the first `dotify.audio.v2` vertical slice: backend publish writes a chunked encrypted `DAV2` object, new registry refs use `dotify:enc:v2:ipfs://`, and the web player recognizes v2 refs -with a Media Source Extensions path plus full-file fallback. Host playback now -emits startup timing events; the remaining P3 work is browser/device validation -against real gateways and media files. +with a Media Source Extensions path plus authenticated full-file fallback. The +MSE path uses bounded two-chunk read-ahead, ordered appends, one imported AES key +per playback, and strict chunk-range response validation. Host playback emits +startup timing events; the remaining P3 work is worker offload, field telemetry, +and browser/device validation against real gateways and media files. ## 2. Current Delivery State @@ -45,7 +47,7 @@ against real gateways and media files. | Free-track key delivery | Delivered | The backend verifies public access on-chain before releasing a key with no wallet or signature. | | Artist runtime bootstrap | Delivered | Polkadot Hub EVM registration is staged: `createRuntime()` creates a minimal shell, then `installRuntimeStep()` installs one pallet per transaction before final ownership transfer and directory registration. | | Room access doctrine | Delivered and preserved | Only the host needs access; listeners receive only the WebRTC stream. | -| Chunked encrypted streaming, P3 | First vertical slice delivered | New backend uploads publish DAV2 refs; web playback supports v2 refs with v1 fallback. Startup metrics exist; browser/device validation remains. | +| Chunked encrypted streaming, P3 | Startup pipeline delivered; field validation open | New backend uploads publish DAV2 refs; web playback supports v2 refs, bounded read-ahead, strict ordered append, and v1/full-file fallback. Startup metrics exist; browser/device validation remains. | | Real Proof of Personhood integration, P4 | Open | Current `human-free` remains structurally ready but not backed by the live platform source. | | Polkadot App / Triangle integration, P5 | Open | DotNS/Bulletin alignment exists conceptually; Product SDK, Host API signing, and Statement Store migration are future work. | @@ -253,9 +255,26 @@ The target browser path: 1. Fetch and parse the header. 2. Fetch encrypted chunks using HTTP Range requests. -3. Decrypt each chunk with Web Crypto. -4. Append decrypted bytes to a Media Source Extensions `SourceBuffer`. -5. Start playback after the first appendable segment. +3. Import the temporary content key once, then decrypt each chunk with Web + Crypto. +4. Prepare the current chunk plus two future chunks concurrently while keeping + at most three prepared chunks in memory. +5. Append decrypted bytes to a Media Source Extensions `SourceBuffer` in strict + chunk order. +6. Start playback after the first appendable segment. + +The range layer requires `206 Partial Content`. Known encrypted chunk ranges +must return exactly the requested bytes, and an exposed `Content-Range` header +must agree with the request. Header reads may be shorter only when the response +reaches the end of a small object. + +MSE treats successive appends as one logical byte stream and retains incomplete +parser input across appends. That makes DAV2's encryption boundaries compatible +with incremental parsing, but it does not make every uploaded file a valid MSE +stream. The bytes still have to conform to the registered format for their MIME +type. `MediaSource.isTypeSupported()` is a necessary capability check, not proof +that a particular file is correctly packaged; recoverable append failures keep +the authenticated full-file path available. Fallback: @@ -313,7 +332,41 @@ Browser validation remains required before marking P3 release-ready: - host switches v1 -> v2 and v2 -> v1 tracks; - listener joins before and after first audio; - mobile autoplay fallback still shows the explicit "start audio" action; -- `replaceTrack()` behavior remains stable when the source changes. +- source switches preserve listener audio through renegotiation, while + same-source sender replacement remains stable. + +### Current streaming coherence review (2026-07-18) + +The playback and room layers remain intentionally separate: + +- DAV2 Range/decrypt/MSE runs only on the authorized host or individual + listener. It never moves source bytes or content keys into the guest room + path. +- A persistent host `