Files
LlamaCasty/HANDOFF.md
T
gramps 716a77f61a fix(pump+compositor): take-3 starvation — deadline pacing + row-blit fast paths
Two defects made the producer 17x slow (37s record -> 2.1s/127-frame file,
rawvideo stamps by arrival): FramePump slept the FULL interval after each
render (period = render+submit+interval) and SceneCompositor did per-pixel
float sampling + Math.Round blends over all 2.07M master pixels, scanning the
whole destination per overlay (258ms avg render vs 1.5ms submit).

Both solutions are established, not invented — researched before coding per
the derivative-work rule:
- deadline pacing: OBS libobs/media-io/video-io.c video_thread (nextTick +=
  intervalTicks, sleep only the remainder, rebase on overrun, never burst)
- row blits: libyuv pattern (BSD-3, chromium.googlesource.com/libyuv/libyuv)
  — 1:1 aligned identity fast path, per-pixel alpha branch, integer
  fixed-point blend, overlay clipped to the intersection rect, skip the dead
  black pre-fill when the backdrop covers

ONE integration test: Pump_Paces_To_The_Deadline_Compensating_Render_Cost
(lands after a fake-seam lesson: pacing fakes must await, not complete
synchronously, or the pump loop runs inline on StartAsync and hangs vstest).
Clean build 0 warnings; FramePumpTests 10/10, SceneCompositor/SceneGraph/
SocialBar/StretchMath 20/20. Docs same commit: ai.md pipeline section,
TASKS.md TASK 18 (webcam-in-output + rename modal verified from take 3),
MyMistakes recipe, HANDOFF rewritten. Take 4 pending on the user's machine.
2026-09-03 09:02:45 -07:00

4.7 KiB
Raw Blame History

HANDOFF — Session State

Branch / Commit State

main — take-3 starvation fix commits land locally (see git log); push only when the user says so. The take-3 audit itself happened 2026-09-02/03: user recorded take 3 (Downloads\recordings\, manually renamed llamacasty-recording-3.mp4), ffprobe + startup.log + an extracted frame did the diagnosis.

What the take-3 audit found

  • 37s recording → 2.1s file, 127 frames @60fps = ~17x time-lapse, audio truncated to match (ffmpeg's rawvideo demuxer was blocked on the starved video input, so only ~2.3s of audio was consumed). The user's "webcam at 6x, garbled" = the same file-level time-compression, most visible on the webcam.
  • The stage-timing seam paid for itself in one line: 17/300 frames per 5s, avg render 258.1ms, avg submit 1.5ms — the encoder/pipe was healthy; SceneCompositor.Render was the whole bottleneck.
  • Two defects, both fixed (2026-09-03) — research-first (OBS libobs/media-io/video-io.c deadline pacing + libyuv row-blit pattern; cited in the commit and MyMistakes.md recipe):
    1. FramePump slept the FULL interval after each render → period = render+interval. Now an absolute nextTick += intervalTicks deadline; on overrun rebase (no catch-up burst).
    2. Per-pixel float sampling + Math.Round blends over all 2.07M master px; BlitOverlay scanned the full destination per overlay. Now: 1:1 aligned row-walk fast path (alpha branch, integer fixed-point blend), BlitOverlay clipped to the intersection, backdrop-cover skips the black pre-fill.
    3. Webcam-in-output VERIFIED from the take-3 frame (bottom-right, border + social bar render too).
  • Test: Pump_Paces_To_The_Deadline_Compensating_Render_Cost (records the requested wait via the pacing seam). Per-class runs: FramePumpTests 10/10, SceneCompositor+SceneGraph+SocialBar+StretchMath 20/20. Clean build 0 warnings. Landmine found the hard way: a pacing fake returning Task.CompletedTask synchronously runs the whole pump loop on StartAsync's continuation and HANGS the vstest run — fakes must genuinely await (Task.Delay(d, ct)) or yield.
  • Minor logged on take-3 stop: FramePump: encoder stop failed: No process is associated — cosmetic teardown race (process already exited before StopAsync's kill); follow-up only if it grows teeth.

OPEN — do next, in order

  1. Take 4 (user records ~30s, record-only) → ffprobe the file (expect frames ≈ 60×seconds, duration ≈ wall time) + read startup.log FramePump stats (expect n/300, avg render ≤ ~16ms). If n/300 climbs only to ~45-55: next slice is the 8.3MB/frame LOH allocation → pool the master buffer.
  2. Then code, one integration test per change (queue from before, unchanged): radio pills / record-OR-stream enforcement (TASK 18 ruling; BeginGoLive(alsoRecord) dies) → top bar Option A pending user approval → empty-state ruling pending (disabled / rehearsal / default-record) → SYNC slider placement ruling pending.
  3. Un-asked questions (don't nag; answers ready): the recorder said the desktop capture "didn't last long enough to tell quality" — take 4 fixes that; "other issues" from takes 1/2 never listed.

State of the app

Boots clean. Recording pipeline: render starvation fixed pending take-4 confirmation; webcam + social bar confirmed IN the output. ffmpeg cached at %APPDATA%\ytLlive\tools\ (month-end pin). Test suite per-class green; do NOT run full-suite vstest (WASAPI teardown hang, pre-existing).

Landmines

  • testhost shares startup.log with the app — filter by time when triaging.
  • Stale testhost/exe locks the DLL (MSB3027): taskkill /F /IM testhost.exe / ytLive.exe first.
  • Do NOT run full-suite vstest (hangs); do NOT claim suite totals — per-class only. verify.sh's step 2 IS the full-suite hang — flow: clean build + per-class vstest + scope-check.
  • Windows binaries (ffprobe/ffmpeg under %APPDATA%\ytLlive\tools\) need WINDOWS paths (C:\Users\...), never /mnt/c/... — the mount path reads as "No such file or directory".
  • Real-MainWindow tests MUST use LayoutPathOverride + temp DB; VolumePushOverride seam exists so volume-slider tests never touch the machine's speakers.
  • AudioPipelineTests was the "known failure" graveyard — a new failure there means a live-loop regression; read the logged stack (throttled, with stack).
  • Pacing-seam fakes must yield/await — synchronous completion runs the pump loop inline (see above).

@ User note

He does not want tangents acknowledged twice (rename question = noise; the ask was ALWAYS the recording). Keep responses SHORT; work the queue; one integration test per change; committing is expected, pushing is his word.