From 349e19097ac664e01b9d6ebd9bdb3fab0c0066f6 Mon Sep 17 00:00:00 2001 From: 4gray Date: Tue, 4 Aug 2026 19:21:53 +0200 Subject: [PATCH] docs(playback): clarify recovery policy exceptions --- AGENTS.md | 21 +++++++++----- CLAUDE.md | 19 ++++++++---- docs/architecture/embedded-inline-playback.md | 29 +++++++++++++------ 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f656cb57d..62e0ba343 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -229,9 +229,12 @@ Key files: treats rejected loads as terminal lifecycle outcomes, preserves exact public DASH text-parser category/code evidence with unknown stage/failure, and never retains or renders raw messages or `error.data`. A failed browser-support - preflight stays unknown but keeps external fallback for clear DASH; KODIPROP - DRM still suppresses it. See the CLAUDE.md "Video Players" feature entry and - `docs/architecture/m3u-playlist-module.md` ("DASH + ClearKey Playback"). + preflight stays generic-unknown but carries the exact app-owned + `PlaybackRuntimeSupport.ShakaBrowserUnsupported` marker, preserving managed + external fallback only for clear transferable DASH; PWA capability and + KODIPROP DRM still suppress it. See the CLAUDE.md "Video Players" feature + entry and the "DASH + ClearKey Playback" section of + `docs/architecture/m3u-playlist-module.md`. - mpegts.js `1.8.0` errors from HTML5, Video.js, and ArtPlayer cross one version-locked structured evidence boundary in `libs/playback/util`. Only exact public type/detail pairs, pair-derived stage/failure, terminal @@ -261,10 +264,14 @@ Key files: alternative sources preserve attempts, while a different content-session key or component teardown resets them. Recovery recommendations never auto-switch, persist history, learn across sessions, or emit telemetry. - Network and unknown evidence fail closed to Retry/alternative source; PWA - capability suppresses managed MPV/VLC, and ClearKey/KODIPROP DRM suppresses - external targets because its payload is not transferable. Raw engine - messages, arbitrary data, and credentials never enter recommendation + The policy projects attempted inline target IDs through the validated + canonical source/target capabilities and excludes every attempted engine + family, so HTML5 and ArtPlayer are not separate hls.js recoveries. Network + and generic unknown evidence fail closed to Retry/alternative source; the + exact Shaka browser-unsupported preflight marker is the sole unknown-code + exception. PWA capability suppresses managed MPV/VLC, and ClearKey/KODIPROP + DRM suppresses external targets because its payload is not transferable. Raw + engine messages, arbitrary data, and credentials never enter recommendation evidence or ownership state. - The built-in HTML5/hls.js player is the second guarded consumer. `HtmlVideoPlayerComponent` provides a component-scoped diff --git a/CLAUDE.md b/CLAUDE.md index 89902727e..cb4f0f126 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -788,10 +788,14 @@ app as a real argument, so it is not an option. alternative sources preserve attempts, while a different content-session key or component teardown resets them. Recovery recommendations never auto-switch, persist history, learn across sessions, or emit telemetry. - Network and unknown evidence fail closed to Retry/alternative source; PWA - capability suppresses managed MPV/VLC, and ClearKey/KODIPROP DRM suppresses - external targets because its payload is not transferable. Raw engine - messages, arbitrary data, and credentials never enter recommendation + The policy projects attempted inline target IDs through the validated + canonical source/target capabilities and excludes every attempted engine + family, so HTML5 and ArtPlayer are not separate hls.js recoveries. Network + and generic unknown evidence fail closed to Retry/alternative source; the + exact Shaka browser-unsupported preflight marker is the sole unknown-code + exception. PWA capability suppresses managed MPV/VLC, and ClearKey/KODIPROP + DRM suppresses external targets because its payload is not transferable. Raw + engine messages, arbitrary data, and credentials never enter recommendation evidence or ownership state. - DASH + ClearKey (M3U module): `.mpd` channels play through a lazily loaded Shaka Player source engine inside the HTML5 and ArtPlayer components (no new @@ -810,8 +814,11 @@ app as a real argument, so it is not an option. recoverable error events, treats rejected loads as terminal lifecycle outcomes, preserves exact public DASH text-parser category/code evidence with unknown stage/failure, and never retains or renders raw messages or - `error.data`. A failed browser-support preflight stays unknown but keeps - external fallback for clear DASH; KODIPROP DRM still suppresses it. Details in + `error.data`. A failed browser-support preflight stays generic-unknown but + carries the exact app-owned + `PlaybackRuntimeSupport.ShakaBrowserUnsupported` marker, preserving managed + external fallback only for clear transferable DASH; PWA capability and + KODIPROP DRM still suppress it. Details in `docs/architecture/m3u-playlist-module.md` ("DASH + ClearKey Playback"). - External players: MPV, VLC (via IPC to Electron backend) - Embedded MPV (experimental, macOS/Windows/Linux): renders mpv video inside the Electron window through a native addon. macOS uses the libmpv render API in an `NSOpenGLView`; Windows uses in-process libmpv with `--wid` against an app-owned child `HWND`; Linux spawns an out-of-process `mpv --wid=` controlled over a JSON IPC socket (X11/XWayland only, requires system `mpv` on PATH; subtitles/speed/aspect/recording are not exported there). mpv's own screensaver inhibition does not apply to any of these paths, so `EmbeddedMpvNativeService` holds an Electron `powerSaveBlocker` (`prevent-display-sleep`) whenever any session's status is `playing`, and releases it on pause, dispose, or shutdown. Renderer bounds are CSS pixels; the service converts them to native units in the main process (`embedded-mpv-bounds.util.ts`: × page zoom everywhere, × display scale on Windows/Linux whose child windows are positioned in physical pixels; frame-copy bounds stay unscaled), and the session controller re-syncs bounds when `devicePixelRatio` changes. Service: `apps/electron-backend/src/app/services/embedded-mpv-native.service.ts`; full architecture: `docs/architecture/embedded-mpv-native.md`. diff --git a/docs/architecture/embedded-inline-playback.md b/docs/architecture/embedded-inline-playback.md index ab6159071..4c7e035f1 100644 --- a/docs/architecture/embedded-inline-playback.md +++ b/docs/architecture/embedded-inline-playback.md @@ -485,10 +485,14 @@ or media cause, so stage and failure remain unknown. A failed public `Player.isBrowserSupported()` preflight is not a Shaka error and therefore retains fully unknown technical evidence instead of being -mislabelled as an unsupported container. Clear DASH can still rank configured -MPV/VLC actions when the structured diagnostic and runtime capabilities permit -them. KODIPROP DRM sources never rank external players because the external -launch contract does not transfer their key configuration. +mislabelled as an unsupported container. The app adds only the exact, +enumerated `PlaybackRuntimeSupport.ShakaBrowserUnsupported` marker to that +otherwise unknown diagnostic. This Shaka/DASH runtime-preflight marker is the +sole unknown-code exception that can rank configured MPV/VLC actions, and only +for clear, externally transferable DASH in a managed-external runtime. Generic +unknown diagnostics remain Retry/alternative-source only. PWA capability and +KODIPROP DRM suppress the external actions because those players are absent or +the launch contract cannot transfer the key configuration. Shaka messages, URLs, headers, request/response bodies, credentials, license/key payloads, and arbitrary `error.data` objects are neither retained @@ -570,20 +574,27 @@ also suppress built-in recommendations. The pure policy builds the following order, filters the current, unavailable, incompatible, and already attempted targets, and then returns at most three -actions. The first surviving action is primary and later actions are secondary. +actions. It also projects attempted inline target IDs through the validated +canonical source/target capability matrix and filters every engine family that +has already been attempted. HTML5 and ArtPlayer therefore cannot be offered as +separate hls.js recovery attempts. The first surviving action is primary and +later actions are secondary. | Sanitized evidence | Candidate order | | ----------------------------------------- | ------------------------------------------------------------ | | HTTP, timeout, or generic network failure | Retry -> Alternative source | -| Unknown playback error | Retry -> Alternative source | +| Generic unknown playback error | Retry -> Alternative source | +| Exact Shaka browser-unsupported preflight | MPV -> VLC -> Alternative source | | Browser access/CORS/CSP-class failure | MPV -> VLC -> Alternative source | | Unsupported codec or container | MPV -> VLC -> Alternative source | | Media/decode/engine processing failure | Distinct built-in family -> MPV -> VLC -> Alternative source | | DRM/encryption failure | Compatible built-in path -> Alternative source -> MPV -> VLC | -Network and unknown evidence fail closed: they never claim that changing a -decoder will repair the provider response. Contradictory or incomplete -capability facts fail closed to Retry and an available alternative source. +Network and generic unknown evidence fail closed: they never claim that +changing a decoder will repair the provider response. The exact app-owned +Shaka browser-unsupported runtime-preflight marker above is the only +unknown-code exception. Contradictory or incomplete capability facts fail +closed to Retry and an available alternative source. External targets require both managed external-player support and a transferable payload. PWA builds therefore never rank MPV/VLC. Any ClearKey/KODIPROP DRM payload is non-transferable and suppresses both external targets; the policy