# HANDOFF — 2026-09-15 (slice-18 C4 composite cache committed locally — device verify next) ## Branch / Commit State `main` HEAD = **slice-18 commit** (C4 blit-on-change composite cache — committed LOCALLY, **NOT pushed**; web/A/V work stays commit-local until greenlight). Before it: slice-17 overlapping capture readbacks, slice-16 capture conversion fix, slice-15 pacing fix (FramePump), `c01206f` (composition capture), `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. ## ✅ Committed locally — slice 18: C4 = FramePump blit-on-change composite cache The ty-1841 take (slice-17 build) proved capture fixed (band ~20 fresh updates/s, no tears, pacing clean) but the render is STILL the wall: **FramePump stall on EVERY iteration** (`totalMs 21-44`, `render=full-render split=0 elements=6 dynamic=4`, worst render 166ms startup spike) — only ~22-28 composites/s. The SceneGraph split can't fix it: `GetSplitPoint` returns **0** because the live-capture backdrop is element 0 and CANNOT be baked (a cached capture goes stale). **What** (`Services/Encoder/FramePump.cs`, + new Good Dog test in `ytLive.Tests/FramePumpTests.cs`): the full-render path now caches the last composite + its INPUT IDENTITY. `BuildFullRenderSignature` mirrors the compositor's own resolution (same resolver seam: element ref + layout/visual bits + resolved frame's array identity + Epoch + CropBounds + options + social bar) — unchanged identity → ONE `Buffer.BlockCopy` (~3ms) instead of the full re-composite (~30ms); changed identity → re-render. Cache buffer is a separate long-lived array, written pre-burn/pre-recycle (never the scratch pool). Gated on the 1:1 config (the only deployed tier). Telemetry: `cache {renders}R/{hits}H` on the 5s stats line + internal `CacheHits`/`CacheRenders`/`OutputIndex`. **Good Dog test:** `FullRenderCache_StaticInputs_RenderOnce_Then_Reuse_UntilInputChanges` — static scene renders ONCE then hits (byte-identical above the burn strip), a new frame (new array + Epoch) invalidates + propagates. Existing `Pump_Pools_...` test now passes a STABLE scene (like production) and keys alternation on `OutputIndex` (the two resolver passes per tick double-advanced a call-count flip). **297/297 green, app + tests build 0 warnings.** Scope-locked (2 code files + ai.md + HANDOFF): `Services/Encoder/FramePump.cs`, `ytLive.Tests/FramePumpTests.cs`. ## ⚠️ Open items (before PUSHABLE) - **Device re-verify (next step):** creator records the SAME tv-show scenario on the slice-18 build. Judge numerically: - startup.log telemetry: `cache` line shows hits dominating on TV holds (`e.g. cache 1R/250H`), `avg render` drops toward the ~3ms BlockCopy, FramePump **stalls disappear** (the per-iteration stall was the C4 signature). - Decode + `/tmp/opencode/freeze_audit.py` / `band_timeline.py`: desktop-band fresh updates/s up toward ~60 (was ~20 first-11s; the render cap was the bind), no mid-frame splits. - ffprobe: video ≈ audio ≈ wall (pacing already healthy at slice 17 — unchanged expected). - If the desktop layer STILL reads choppy after cache hits dominate every static hold, the residual is the **24fps TV → 60fps container pulldown** (inherent 3:2-ish repeats; the 1841 gap histogram was 89×2-slot + 84×3-slot holds) — that's content, not the pipeline; decide with the creator whether it needs an adaptive cadence or is acceptable. - **No push yet** — commit-locally-until-greenlight for web/A/V work. After the take verdict, also re-measure the clap offset (`/tmp/opencode/avsync.py`), then decide push with the user. ## 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. - Focus-loss capture lag — closed as NOT the cause (1824: delivery healthy ~60-100/s). ## 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). - 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`. - FramePump tests that assert per-frame CONTENT must pass a STABLE scene (`() => scene`) — the default NewPump scene is fresh-per-tick (ok for pacing tests, but it churns the C4 render signature and hides the cache). Cache-sensitive assertions also can't use a call-count resolver flip (the tick resolves twice: signature + render) — key alternation on `OutputIndex`. - ffmpeg/ffprobe: `/mnt/c/Program Files/Krita (x64)/bin/` with Windows paths. - `MyMistakes.md` has the **freeze-audit RECIPE**, the **A/V sync measurement recipe**, the **deadline-pacing** lessons, the **CoreMessaging DQ recipe**, and the **WGC-CLIP** + slice blocks — grep before re-deriving. - sqlite3 at `/home/gramps/android-sdk/platform-tools/sqlite3`. - `C:\tmpout` is for ffmpeg evidence artifacts (raw decodes / PNGs); keep them out of the repo. ## Next step Creator records a tv-show take on the slice-18 build → read the startup.log telemetry: shift-stall frequency and the `cache NR/WH` line (hits must dominate on TV holds) + the band audit + ffprobe durations. If the desktop now tracks ~60 updates/s and stalls are gone: re-measure the clap offset, then decide push with the user. If the layer is still choppy on fully-static holds, the pulldown (readme) is the residual and it's a content decision, not a pipeline bug.