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.
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 —
f3d578chas per-5sAudio 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_MasterPixelspixel (1380,700) cyan-vs-magenta (pre-existing, recorded in ai.md slice 9); vertical-tierBilinearScalefresh allocation per frame.
Landmines
- testhost shares startup.log with the app — filter by time.
taskkill //F //IM ytLive.exebefore rebuilds; re-run ifMSB3021copy-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), recordingsty-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.