# HANDOFF — 2026-11-05 (TASK 21 — video file layer + its audio) ## State - `main`; TASK 21 is complete. A video file added from the (+) menu decodes, composites into preview and stream, loops on toggle, and **plays its own soundtrack** (Mute + Level per layer, mixed into the desktop/game group so the desktop fader and the ducker apply). Removing it stops the decoder. - Decoding is now ONE pipe: `Services/VideoClipPipe.cs` behind both `MediaVideoSource` (TASK 21) and `AlertClipDecoder` (TASK 47) — "a clip is a clip". Alert behaviour is unchanged and its tests stay green. - Tests: `MediaSourceAcquisitionTests` (add → decoder starts, frames, loop, remove) and `MediaSourceAudioTests` (chunks, level scaling, mute, sound reaching the desktop meter). App build 0 warnings. ## Next action - Next queued unit: TASK 49 (chat profanity filter). Day 3's TASK 32/33 resilience slices are still outstanding — 32·4 (fragmented MP4) is the smallest. - Agreed next feature work (designed, not started): green/blue screen detection + keying through the clip pipe — suggest-only by default, an opt-in "Auto Green/Blue Screen" setting, alert clips included. - Do not push absent a checkpoint request. ## Landmines - `LayerReorderPersistenceTests.RealMouseDrag_OnTheLayerList_PersistsTheReorder` injects physical mouse input. Do not run it while the desktop is in use. - Integration tests constructing `MainWindow` must set a temporary `LayoutPathOverride` and clear it in `finally`. - Media sessions are keyed per **path**, not per layer: acquire through `EnsureMediaSession`, release through `ReleaseMediaIfUnused`, never `AcquireAsync` twice for one path. Level/mute are therefore per session too. - Bundled FFmpeg stays outside the single-file exe (`ExcludeFromSingleFile="true"`).