diff --git a/HANDOFF.md b/HANDOFF.md index d22b1da..6f98c5e 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -1,53 +1,84 @@ -# HANDOFF — 2026-10-16 (work committed locally; NOT pushed — push at the next milestone) +# HANDOFF — 2026-10-17 (PLANNING ONLY session; nothing pushed — push at the next milestone) ## At a glance - **Branch** main, tracking `origin/main`. **origin/main = `931ab46`; HEAD = the tip commit - "Read the first instrumented take: the judder did not reproduce, no element is slow"** — - **4 ahead, 0 behind** (nothing pushed this session; per the commit/push policy, push only when the - creator says so). This file cannot record its own commit's hash — amending a commit changes that - hash — so the tip is named by subject. - - The four local-only commits: `3cb29ea` (**previous session's HANDOFF refresh — the old handoff - claimed it was pushed; it never was**), `a3a4681` (per-element composite timing + scene dump), - `84cbec2` (FramePumpTests thread-safe log sink), the tip. Always check - `git log origin/main..HEAD` — never a handoff's own "0 ahead" claim. + "HANDOFF: vv webcam plan, and drop the stale vertical-preview landmine"** — **5 ahead, 0 behind** + (nothing pushed; per the commit/push policy, push only when the creator says so). This file cannot + record its own commit's hash, so the tip is named by subject. + - The five local-only commits: `3cb29ea` (previous session's HANDOFF refresh), `a3a4681` + (per-element composite timing + scene dump), `84cbec2` (FramePumpTests thread-safe log sink), + `cdf82f6` (read the first instrumented take), the tip. Always check + `git log origin/main..HEAD` — never trust a handoff's own "0 ahead" claim. - Working tree clean after the tip commit. -- **The creator's first take of the instrumented build happened today** (18:40–18:44, Release - recording). **The judder did NOT reproduce and no element is slow** — full reading in `ai.md` → - "✅ What the first instrumented take said". Nothing is queued to fix from it. +- **This session produced NO code, NO build, NO test run.** It specified the creator's **vv + (vertical 9:16) webcam feature** end to end; implementation has not started. The locked rules are + below — they are the deliverable, and they must land in `TASKS.md` when work is queued. -## This session (2 commits — both unpushed) -1. **`84cbec2` — FramePumpTests race fix (own commit, creator-approved).** A full-suite failure - (`Stats_ReportRealRendersAndDistinctWebcamFrames…`, "Collection was modified") was a **test-side - data race**: a plain `List` enumerated by the test while the pump logged from its own - thread. Fixed with `ConcurrentBag`. **Proof: full suite 428/428 passed, 0 warnings.** - Lesson recorded in `MyMistakes.md` → "known failure label" (2nd instance). -2. **The reading (this is the tip commit).** Take `ty-20261016-1841-559-0002.mp4` (174.5s, Release - `e95154d9`, 1920×1080 1:1, recording): **60 composites/s, avg render 1.0–1.1ms, biggest element = - webcam 0.4ms**, backdrop 0.2ms, other four under the 0.1ms floor, `cache 151R/150H`, webcam 30.0/s - at the resolver (longest gap 50ms), and the FILE holds **29.6 distinct webcam images/s with 82% of - images held exactly 2 frames**. No culprit element exists in this take. - - **The historic slow numbers are different configurations:** Oct 9 19:48 (still on disk) was the - **vertical** tier (`comp=608x1080`, 45ms, 92 renders/5s); Oct 5 12:01's geometry was never logged - (the `scene=/comp=` suffix didn't exist) so the map's 21:9 story stays a hypothesis. Every slow - window shows `cache xR/0H`; one Oct 5 take latches fast→slow (1.5ms → 45ms) within 15s. - - **Corrected in the map (not appended):** "it was never Debug-vs-Release" is withdrawn (same - 1920×1080 tier: Oct 9 = 10.4ms vs today's Release 1.0ms, and `Build ` records no - configuration), and the "same scene shape" 10:01/12:01 comparison is superseded. - - **Same commit ships the probe + its recipe.** `scripts/webcam-cadence.py` (new tool): the - ground-truth check for what the FILE holds. Its three traps (H.264 re-encoding defeats - exact-pixel comparison; a round-clip crop's corners leak 60fps background; a fixed crop across a - scene switch reads background) cost three wrong readings — all in `MyMistakes.md`, with an - ffmpeg-native cross-check (`tblend=difference` + `signalstats.YAVG`) that agreed (52.2% - duplicates / 28.6 distinct/s). +## vv webcam feature — locked rules (creator, 2026-10-17) +| mode | shape | size | position | +|---|---|---|---| +| 16:9 | as today | as today | as today | +| **vv · Live** | **circle OR rect, creator's choice** | small tile | one of six spots: top/bottom × L/C/R | +| **vv · Chat** | **rect only — no circle option** | normal, or enlarged to fill one area (607×540) | enlarged → top or bottom | +| Starting / BRB / Ending | unchanged | unchanged | unchanged | + +- **Placement is set by tap/click-drag with snap, exactly like the socials today**, plus manual entry + in properties. Creator's explicit precedent, not an inferred one. +- **vv keeps its own camera position, size and shape per scene** — creator-confirmed: switching back + to 16:9 restores the desktop layout exactly as it was. +- **No explicit borderless/no-background mode is needed**: round + border/bg options already let the + creator strip both (creator's ruling — this deletes that item from the original request). +- Creator's "square" means the rectangular view (the camera's own aspect), not a literal 1:1 box. + +## What the code already gives us (established this session — do not re-hunt) +- **vv = the active tier's centred band crop.** 1080p60-vertical: master band **x 656.25–1263.75 + (607.5 wide), full height**, upscaled to 1080×1920 (`MainViewModel.Streaming.cs` `ApplyStreamQuality` + → `OutputRect*`). The band splits into **two 607×540 areas** (top/bottom) — the creator's "two mini + 16:9 views", each exactly 50% of the frame. +- **The Live webcam sits at x≈1425 → entirely outside the band.** That is the whole motivation: in vv + the camera is not misplaced, it is invisible. +- **Geometry only — no render-path change.** Preview (`Controls/PreviewPane.xaml` 144–230) and + compositor (`Services/Compositor/SceneCompositor.cs` 389–397, `DrawBorder`) both read the element's + own `X/Y/W/H` + `ClipShape`, so parking the camera needs no compositor or preview work. The + two-tile look *falls out of* the camera covering half the band — the capture element, chat box and + blit path stay untouched. +- **Round / border / background are independent**: `ClipShape.Round`; `HasBorder` = width > 0 AND a + valid 6-hex colour; `BackgroundEffect` = None/Remove/Blur. +- **Per-scene camera size policy already exists**: `MaxWebcamWidthFor/HeightFor` (Chat 1358×764, + others 960×540) + `ClampWebcamToBounds`. **A 607×540 tile sits inside both → the clamp needs no + change.** +- **Storage**: `WebcamSceneConfig` table; new columns go in `MigrateWebcamConfigTable()` as idempotent + `ALTER TABLE … ADD COLUMN` guarded on `PRAGMA table_info` — the established "additive, no version + bump" idiom (`RectWidth/RectHeight`, TASK 51's `BackgroundEffect` landed this way) — plus + `LayoutStore.Save.cs` INSERT and `LayoutStore.Load.cs` SELECT. +- **Existing per-element precedent for remembered geometry**: `RectWidth/RectHeight` + + `ToggleClipShape` (`Models/SceneElement.cs` 124–152) — the pattern for keeping the 16:9 layout + while vv owns its own. + +## Units (each: ONE Good Dog integration test, own commit, memory in the same commit) +1. **vv camera layout** — stored separately per scene, resolved when the tier changes. Live: small + tile (circle or rect) snapped to one of six spots; drag like the socials + properties entry. + *Test:* with the vertical tier active, dragging the Live camera to top-right places it top-right + inside the band; switching back to 16:9 restores the original layout. +2. **vv · Chat** — rect enforced with the circle option unavailable, plus enlarge-to-one-area + (607×540) snapping top or bottom. + *Test:* in Chat under the vertical tier, enlarge sets the full top area and the circle option is + not offered. + +## Corrections made this session +- **Withdrawn landmine (creator-confirmed):** the old line "Vertical-format regression (STALE, not + fixed): 1080p60-vertical selection no longer shrinks the capture border in the preview" was **never + verified**, and it cost this session a pointless question. The creator confirms vv *does* dim the two + bands astride the centre band and that this is expected/best practice. If the original symptom was + something else (the capture element's own border?), it is **unexplained, not known-broken** — do not + re-raise it as a dependency. +- The prev-session content (first instrumented take: judder did not reproduce, no element slow; probe + + recipe; the four local commits) is unchanged and lives in `ai.md` → + "✅ What the first instrumented take said". ## Next step -- **Creator take in the FAILING geometry — the vertical 1080p60 tier first** (creator's pick from the - two options offered). Then, if the creator is willing, the 21:9 display config. -- Read three lines in `%APPDATA%\ytLlive\startup.log`: `FramePump parts (N renders/5s): …` (which - stage/element eats the budget), the `FramePump scene dump:` block (the shape), and `cache NR/NH` - (0 hits = the slow state's signature). **No fix until that take names the stage** — the latch - hypothesis (a composite pushed past the camera period can never reuse the whole-frame cache again) - is unproven and the `parts` line is what decides it. +- **Implement Unit 1 on the creator's go-ahead.** Nothing is queued in `TASKS.md` — the creator queues + work, and this plan lives here until then. Queue it in `TASKS.md` as part of the first Unit 1 commit. ## Open (operational) - **verify.sh's known-failure whitelist is too loose (confirmed twice on 2026-10-16):** it passes when @@ -55,22 +86,18 @@ known flake (`LayerReorderPersistenceTests.RealMouseDrag_OnTheLayerList_PersistsTheReorder`, which passes in isolation) it reports "NOT the known pre-existing pair". **Follow-up: require EVERY failure line to be whitelisted**, and add `MasterLimiter_CapsTheLiveMix_OnThePipe` + - `RealMouseDrag_OnTheLayerList_PersistsTheReorder` to the list. Not fixed here — `scripts/verify.sh` - was never in a declared file list. -- **A pre-existing stash from older work is still sitting there:** `stash@{0}` = "WIP on main: - 0464593 Compositor: fast-path opaque 1:1 when source fills canvas" (NOT this session's; do not drop - it blindly). -- **Vertical-format regression (STALE, not fixed):** 1080p60-vertical selection no longer shrinks the - capture border in the preview (`Controls/PreviewPane.xaml:319-322` + `MainViewModel.Streaming.cs` - `ApplyStreamQuality`). Root cause unknown — paused. Note the vertical tier is ALSO the only slow - take still on disk, so if the next take reproduces the 45ms there, this area gets touched twice. + `RealMouseDrag_OnTheLayerList_PersistsTheReorder` to the list. +- **A pre-existing stash is still sitting there:** `stash@{0}` = "WIP on main: 0464593 Compositor: + fast-path opaque 1:1 when source fills canvas" (NOT this session's; do not drop it blindly). +- The judder reproduction take in the FAILING geometry (vertical 1080p60 first) is still outstanding — + **no fix until a take names the stage** (see `ai.md`; the `parts` line decides the latch hypothesis). - ⛔ Sudo password rotation pending (user; then update both `CREDENTIALS.md` password lines). - TASK 56 secret scan before `gramps/LlamaCasty` goes public. - TASK 55 disk hygiene (`startup.log` uncapped — 23MB and the new lines add to it every 5s). ## Tests -- Full suite **428/428 passed, 0 warnings** (2026-10-16, the gate run for `84cbec2`) — a completely - clean run, including the audio tests that usually flake. +- Last full run: **428/428 passed, 0 warnings** (2026-10-16, the gate run for `84cbec2`). **No run this + session (planning only).** - Known flaky-by-environment (all pass in isolation): `AudioPipelineTests.Mix_HonorsProviderGains…`, `MasterLimiter_CapsTheLiveMix_OnThePipe`, `LayerReorderPersistenceTests.RealMouseDrag…`, `Round_Clip_Corner…`. **Read verify.sh's output — it can pass with an unlisted failure present, or @@ -81,6 +108,10 @@ `%APPDATA%\ytLlive\ytLlive.auth` (DPAPI). Startup log: `%APPDATA%\ytLlive\startup.log` (23MB). - Recordings land in `C:\Users\gramp\Downloads\recordings\` (`ty--