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

69 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.