# HANDOFF — 2026-09-14 (composition capture DEVICE-VERIFIED ✓; slice-15 pacing fix committed locally — A/V re-measure next) ## Branch / Commit State `main` HEAD = **slice-15 commit** (FramePump duplicate-on-lag pacing — committed LOCALLY, **NOT pushed**; web/A/V work stays commit-local until greenlight). Before it: `c01206f` (composition capture redesign, also local/unpushed), before that `b22d08e` (signed audio-sync, pushed). Working tree **clean**. ## ⚠️ Branding (2026-09-14, creator-corrected): product = **llamacasty**, internals = ytLive The product is **llamacasty**; repo path, csproj `AssemblyName`/`RootNamespace`, DB/log paths (`%APPDATA%\ytLlive\...`), and most code names are the legacy **ytLive/ytLlive**. User-facing language says "llamacasty"; code/assembly/repo names stay ytLive. See `ai.md` → Brand. ## ✅ DEVICE-VERIFIED — composition capture looks good; then the A/V defect surfaced The creator ran real takes off the `c01206f` build and reports the video looks **very good** — the Windows.Graphics.Capture web path is confirmed on device (open item closed). BUT the same takes showed the A/V defect we have seen before: **both desktop and webcam playback are accelerated, the audio "gets speedier", then cuts off at the end.** ## 🔬 Sliced and measured (evidence) With the A/V recipe (`MyMistakes.md` → "Measuring audio-video A/V sync" + `/tmp/opencode/avsync.py`): - `ty-20260914-1723-0000-2.mp4`: 697 video frames @60fps = **11.62s** vs audio **11.84s**. - `ty-20260914-1726-0000-2.mp4` (clap take): 163 frames = **2.72s** vs **2.93s** audio. Video ends 0.21–0.24s before audio → the cut-off. Clap: audio env peak 1.655s vs video motion 0.75–1.03s; cross-correlation lag **+0.667s** (audio late). - `startup.log`: `FramePump stall: iteration 33-46ms (> 2× the 17ms interval): worst render 33ms … dropped 0`. **Root cause (slice 15):** slice 10's freshness choice skipped the overrun's missed slots — one fresh frame per ~35ms stall authored into a 60fps container = **accelerated playback**. OBS's answer is duplicate-on-lag (`libobs/video-io.c`, docs.obsproject.com/backend-design): fill each missed slot by repeating the newest frame — duration == wall, judder never fast-forward. ## 🔬 Committed locally — slice 15: one frame per deadline slot (duplicate-on-lag) **What:** `Services/Encoder/FramePump.cs` submit is now a bounded catch-up — `while (now >= nextTick) { submit latest composite; nextTick += intervalTicks; }` clamped to a `deadlineNow` captured once per iteration. First missed slot gets the fresh composite, the rest get repeats of it (OBS duplication) — recording duration == wall time under any render load, no acceleration, no audio tail cut. The burned `_outputIndex` moved inside the submit loop (every emitted slot gets its own +1; also fixes the old unconditional bump that gapped the judge sequence on non-submitting fast-render iterations). **Good Dog test:** `ytLive.Tests/FramePumpTests.cs` → `Pump_Overrun_Renders_EmitsEverySlot_NotSkipped` (60fps, 35ms render cost, asserts ≥0.65 of the wall slots emitted — the old skip-pump wrote ~1/35ms). **294/294 green, app build 0 warnings.** Files: `Services/Encoder/FramePump.cs`, `ytLive.Tests/FramePumpTests.cs`. Docs in same commit: ai.md Slice 15, MyMistakes (supersedes the slice-10 "no burst re-write" clause + latest numbers), this HANDOFF. ## ⚠️ Open items (before PUSHABLE) - **Device re-verify:** a take on the slice-15 build must play at REAL time (no acceleration, no cut-off audio tail). Confirm via ffprobe: video stream duration ≈ audio ≈ container. - **Re-measure the true A/V offset** with a clap take now that video pacing is honest (`/tmp/opencode/avsync.py`). The +0.6s reading on 1726 was confounded by the 1.1x acceleration. If a real residual remains after the pacing fix, the backlog is the AUDIO pipeline (mixer ring / advance), not video. - **No push yet** — commit-locally-until-greenlight for web/A/V work. ## Open threads (carried) - Audio-silence verification — fixed (`724af14`); creator heard real audio. - Webcam MJPG missing / ~10–14Hz, layer SortOrder, truncation-with-dynamic-scenes — queued. - Sync control user-doc tutorial — REQUIRED before 1.0 (creator directive; TASK 22). - Signed A/V sync: verify the negative (advance) direction on device. ## Landmines - testhost shares startup.log — filter by time. - `cmd.exe /c "taskkill /F /IM ytLive.exe"` (WSL double-slashes mangle) before rebuilds — a live app process locks `ytLive.exe` and the apphost copy fails (MSB3021, seen today). - Build/tests: **Windows dotnet host** (`/mnt/c/Program Files/dotnet/dotnet.exe`). 0 warnings — only `./scripts/verify.sh ""`'s clean build counts. Building `ytLive.csproj` alone does NOT rebuild `ytLive.Tests.dll` — run the Tests csproj before `vstest`. - ffmpeg/ffprobe: `/mnt/c/Program Files/Krita (x64)/bin/` with Windows paths. - `MyMistakes.md` has the **A/V sync measurement recipe**, the **deadline-pacing** lessons (item 1 + slice 15), and the **CoreMessaging DQ recipe** — grep before re-deriving. - sqlite3 at `/home/gramps/android-sdk/platform-tools/sqlite3` for `/mnt/c/Users/gramp/AppData/Roaming/ytLlive/ytLlive.db`. ## Next step Have the creator record a clap take on the slice-15 build → ffprobe durations (video == audio == wall) + `/tmp/opencode/avsync.py` for the honest offset. If durations match, the acceleration defect is closed; then decide push with the user, and attack any true audio-latency residual as its own work unit.