# HANDOFF — 2026-09-10 (evening) ## Branch / Commit State `main` HEAD currently = `c45cbc9` (slice 10). **Slice 11 is uncommitted** in the working tree (WebView2 capture cadence + de-throttle; see below). **ahead of origin by 16, NOT pushing** — user ruling (2026-09-10): do not push until the web-overlay **transparency AND audio-silence** issues are addressed. Both are open (see Still Open). Milestone tag `milestone-recording-timing` (annotated) on `c45cbc9` — rollback point: `git reset --hard milestone-recording-timing`. ## Timing saga — CLOSED (verified) - slice 9 `bd396e4`: duration == wall time (count-based CFR, deadline never rebased, `-re` removed). - slice 10 `c45cbc9`: bounded `Channel` encoder queue + drop-newest policy + burned-in dot-matrix frame counter (bottom-right). Verified on two takes (`ty-20260910-0949…-2.mp4`, 2383 frames 39.92s; `ty-20260910-0957…-2.mp4`, 2270 frames 38.05s): **every frame decodes, counter advances +1/frame, zero gaps/dups**. Content cadence both: median 2 frames, max gap 9, longest frozen run 8 (133ms). User: "I think we're good on this issue" → **timing CLOSED.** ## The web-overlay threads (the active push-gate work) — Slice 11 in tree Two user-reframed symptoms converged on ONE root cause and one change is in the tree (uncommitted): 1. "The widget is an animated resource — the animation looks **too slow**." 2. (earlier) "image renders but the **transparent pixels are black**." Root cause of #1 (code-proven): the recording is 60fps, but the WebView2 capture loop was a blind 100ms `DispatcherTimer` = 10Hz → the widget's motion is sampled 6× under rate → repeated-frame slow-mo. PLUS Chromium hidden-page throttling (rAF parked, timers→1s; WebView2Feedback#1172/#3070) when the off-screen page's host window is unfocused/covered. #2 remains UNVERIFIED (the diagnostic PNG+alpha log is bound to the FIRST capture ever = the initial about:blank doc, so it can never see the widget — 5/5 sessions logged alpha=0 blank; instrument is blind, not the capture). **Slice 11 (uncommitted, files below):** - `Services/CaptureScheduler.cs` (new): per-session dispatcher timer that DROPS ticks while a capture is in flight (latest-wins, never queues). Interval owner-configurable: 33ms recording / 200ms idle. - `Services/WebView2Manager.cs`: scheduler replaces the raw timer; shared `CoreWebView2Environment` created BEFORE `EnsureCoreWebView2Async` with `--disable-backgrounding-occluded-windows --disable-renderer-backgrounding --disable-features=CalculateNativeWinOcclusion` (`GetEnvironmentAsync`); `SetCaptureInterval(int)`; capture-cost telemetry (first 30 captures/ session → startup.log). - `ViewModels/MainViewModel.Streaming.Operations.cs`: `SetCaptureInterval(33)` on record/stream start, `(200)` on stop. - `ytLive.Tests/WebView2ManagerTests.cs`: ONE test `CaptureScheduler_Drops_Ticks_While_Capture_InFlight_And_Resumes` (deterministic TCS-driven, no WebView2 runtime). - Docs same commit: `ai.md` slice 11, `MyMistakes.md` recipe "web widget captured at 10Hz…". Suite: 290/291 pass — sole failure the PRE-EXISTING `Composite_FullScene_MasterPixels` pixel (1380,700) cyan-vs-magenta (out of scope; fails with any fix stashed). ## NEXT STEP (the take that closes the web animation speed) 1. Commit slice 11 (scope-check first; commit cites WebView2Feedback#1172/#3070/#20 + Chrome-88 blog). 2. Run a normal recording with the animated widget on screen for ~20s. Expected: - startup.log: `capture #1..#30 … took Nms` lines (tell us the per-capture cost) — **this decides whether 30Hz stays or drops to ~20Hz**; also `FramePump stats:` should show no new dropped-frame growth vs before (GC-churn check). - Widget animation ~2-3× closer to real-time (10→30Hz). - If it only became jittery instead of fast: check the FramePump dropped-frame counters. 3. Then, separately, the TRANSPARENCY verification (still open): re-point the first-capture dump/ alpha-log at a POST-PAINT capture of the real widget document (currently bound to about:blank) — the change that makes "are transparent margins real?" answerable. Intended next change. ## Still Open - **Web transparency UNVERIFIED** — the diagnostic instrument is blind (fires on about:blank); last known visual state take-25 black box; user's "transparent pixels black" may be the opacity bug OR the preview surface. Needs the post-paint instrument fix (above) then a take. Push gate reason #1. - **Audio silence** — silent audio (−91dB full-length) in take-15; named-pipe audio delivers ~nothing. Queued follow-up. Push gate reason #2. - Pre-existing compositor pixel test failure (never in scope). ## Landmines - testhost shares startup.log with app — filter by time when triaging. - Locked DLLs: `taskkill //F //IM testhost.exe //IM ytLive.exe` before rebuild. - Build/tests via `/mnt/c/Program Files/dotnet/dotnet.exe build …` / `… vstest "C:\Users\gramp\Documents\Code\projects\ytLive\ytLive.Tests\bin\Debug\net8.0-windows10.0.19041.0\ytLive.Tests.dll"`. - Probing recordings: `/mnt/c/Program Files/Krita (x64)/bin/ffmpeg.exe` / `ffprobe.exe` (Windows-form paths). - `tools/ticker`: constant ~+982ms offset on the FIRST line is cosmetic. - WebView2Manager Ran into LOH churn worry: each capture allocs a BitmapImage raster (~8.3MB) that is garbage per capture; at 30Hz that's ~250MB/s LOH on the UI thread → potential gen2 pauses showing as FramePump dropped frames. Slice 12 candidate if the take's stats show it.