Files
LlamaCasty/HANDOFF.md
T
gramps efe88b8a0b fix(compositor): keep straight alpha in the paste-cache raster — the web widget's recording black box
The element-space raster builds on a TRANSPARENT base but BlitContentRaw's
partial-alpha branch applied the opaque-dst source-over blend: color premultiplied
by the sampled alpha, then alpha forced to 255. Pasting that raster saw a==255 and
straight-copied darkened ink over the scene — a recording box that the raw-bitmap
preview (correct alpha) never showed. Transparent margins and opaque content were
unaffected, which is why every take looped on the page/CSS while the capture was
transparent all along (15:51 dumps: alpha max 255, mean ~19, zero 57%).

BlitContentRaw now takes transparentDst; the raster call passes true and writes
straight color + straight alpha so the paste rows (BlendRowOpaque/Weighted) do the
real source-over onto the opaque master. Master paths byte-identical.

ONE integration test PasteCache_SemiTransparentLayer_RevealsBackdrop_NotOpaqueInk:
50%-blue over red reads (127,0,128) fixed vs (0,0,128) buggy — proven both ways
(verified by stashing the fix: fails before, passes after). Clean build, 0 warnings;
22/23 compositor-class tests pass, the sole failure the documented pre-existing
Composite_FullScene_MasterPixels pixel (1380,700).

Alpha-compositing model: standard source-over with producer-cached surfaces, the
OBS/libyuv paste model already cited in ai.md/MyMistakes (rawvideo recipe, row-blit
BLEND_NONE / straight-alpha branches); full story in MyMistakes (RESOLVED entry).

Per the good-dog rule: one integration test, memory updates (MyMistakes/ai.md/
HANDOFF) in the same commit.
2026-09-12 08:57:58 -07:00

4.6 KiB

HANDOFF — 2026-09-12 (transparency: ROOT CAUSE FOUND + FIXED, awaiting the verify take)

Branch / Commit State

main HEAD lands THIS WORK UNIT: the compositor alpha fix (see ✅ below) + its ONE integration test + memory updates (MyMistakes.md, ai.md, HANDOFF.md). Ahead of origin by ~22 commits. NOT pushing — user ruling: no push until web-overlay transparency AND audio-silence are addressed. Nothing uncommitted at end of session.

✅ HONEST STATUS — THE TRANSPARENCY BUG IS IDENTIFIED

Root cause found by reading the unread code path to the end (the handoff's live suspect, now convicted):

SceneCompositor.BlitContentRaw (SceneCompositor.cs, partial-alpha else if (sa > 0) branch) applied the OPAQUE-dst source-over blend onto the paste-cache raster's TRANSPARENT base: dst = (src*sa + dst*inv)/255 with dst black → color premultiplied by sa, then dst[+3] = 255. A 50%-alpha widget pixel became darkened color + FULL alpha; at paste time BlendRowOpaque saw alpha 255 → straight copy → the scene behind was overwritten by darkened ink. Transparent margins (alpha 0) and opaque content (alpha 255) survived, which is why every take showed a box while the dumps (raw capture) and the preview (raw WriteableBitmap) stayed correct. The CSS-wipe fixes (b4bba4b/0f72c53) were red herrings — they treated the PAGE as the villain, but the capture was transparent from the start (the 15:51 dumps already proved it).

The fix (committed): BlitContentRaw gained transparentDst=false; the raster call passes true and writes straight color + straight alpha so the paste rows (BlendRowOpaque/BlendRowWeighted) do the real source-over onto the opaque master. The two blend rows were verified correct all along (HANDOFF accepted facts held); the divergence was the sampler feeding them. Master paths are bit-identical (transparentDst defaults false).

Verification: clean build 0 warnings (app + tests); SceneCompositorTests + SceneGraphTests + FramePumpTests + ChatOverlayLayerCacheTests = 22 pass, the ONE failure is the documented pre-existing Composite_FullScene_MasterPixels pixel (1380,700) (reproduces with the fix stashed — see ai.md slice 9). The new PasteCache_SemiTransparentLayer_RevealsBackdrop_NotOpaqueInk test FAILS on the old code (exact signature: pixel (16,16): expected rgb(127,0,128), got rgb(0,0,128)) and PASSES on the fix — non-vacuous, proven both ways.

NEXT STEP — ONE take (verify, no further analysis)

The Good Dog Rule is satisfied (ONE integration test shipped with the fix). Record the Live scene with the widget animating, pre-record ~35s so the 30s re-arm dump fires mid-take, then read the verdict:

  • Element rect shows the scene backdrop behind the widget art (no black box/void, no darkened edge ring) → transparency CLOSED, push gate #1 clears.
  • If anything persists, the fix's own test contract is the diagnostic: a translucent pixel must read as scene-through-src, never inked — bring the take.

Other threads (paused)

  • Audio silence — f3d578c has per-5s Audio live: telemetry; next take with desktop audio ACTIVE names the stage. Push gate #2.
  • Webcam missing — "MJPG negotiation refused (being used by another process)". Queued.
  • Web capture speed — ~10-14Hz effective, user satisfied. Revisit only on request.
  • Layer order — dragging an element over another does not persist SortOrder; user explicitly asked it not be buried. Queued after transparency.
  • Known backfills when queued work resumes: Composite_FullScene_MasterPixels pixel (1380,700) cyan-vs-magenta (pre-existing, recorded in ai.md slice 9); vertical-tier BilinearScale fresh allocation per frame.

Landmines

  • testhost shares startup.log with the app — filter by time.
  • taskkill //F //IM ytLive.exe before rebuilds; re-run if MSB3021 copy-lock.
  • Build/tests: /mnt/c/Program Files/dotnet/dotnet.exe build … / vstest. 0 warnings rule. FULL-suite vstest can hang (WASAPI teardown, pre-existing) — per-class filters are the norm (--TestCaseFilter:"FullyQualifiedName~…").
  • Probing: /mnt/c/Program Files/Krita (x64)/bin/ffmpeg.exe / ffprobe.exe — Windows exes take Windows-style paths (do NOT re-download Linux ffmpeg — user aborted that).
  • Evidence artifacts (keep): %TEMP%\ytLive-web-8d7234ec-…-w1..5.png (15:51), recordings ty-20260910-12\51|1534|1551-*.mp4, decoded frames at /mnt/c/Users/gramp/AppData/Local/Temp/w151.raw.
  • The full transparency story lives in MyMistakes.md → "SPIN GUARD → RESOLVED" (now including the 2026-09-12 RESOLVED entry). GREP IT FIRST. Do not re-derive a fourth time.