# HANDOFF — session state > Current operational state, read right after `TASKS.md`. Trust this file as the > truth of what is in flight — do not re-derive from git/fs unless it points at > a problem. Conventions: [`schema.md`](schema.md). Rewrite this file at session > end, compaction, or any interruption. ## Session state (last updated: 2026-08-13) - **Branch:** `main`, in sync with `origin/main`. - **TASK 8 (new, after TASK 7 shipped):** `AudioLevelMeter.ToDisplay` gained **+10 dB input amplification** so the meters use the full bar — speech peaks (~0.2 RMS) now read ~0.93 (red) and normal speech (~0.05) ~0.73 (yellow) at maxed volume; ≤0.001 linear still reads 0 (idle never shows noise). One knob shared by the mic bar and game bar; `× MicVolume` untouched. Tests updated + new `ToDisplay_Pushes_Speech_Peaks_Into_Red_At_Maxed_Volume`. **Uncommitted** (pending user review): `Services/Audio/AudioLevelMeter.cs`, `ytLive.Tests/AudioMixerTests.cs`, `ai.md`, `Services/index.md`, `ViewModels/index.md`, `TASKS.md`, `HANDOFF.md`. Meter tests: 7/7 passing, build 0 warnings. - **This session (TASK 7 — UI polish batch, gramps's 6-point review):** 1. **Scenes list cleaned:** the per-row edit/trash/visibility icons and the inline rename TextBox are gone. Scenes are pure selection rows; `IsHidden` stays persisted and still dims a hidden row to 45%. Removed dead surface: `EditSceneCommand`/`RemoveSceneCommand`/`ToggleSceneVisibilityCommand` + `BeginEditScene`/`ToggleSceneVisibility`/`RemoveScene` handlers + `Scene.IsEditing`. 2. **Sources list upgraded:** each row now has edit + visibility eye + trash. New `EditElementCommand` (`SceneElement.IsEditing` → inline rename TextBox, Enter/Esc/ lost-focus commits) and `ToggleElementVisibilityCommand` (flips `SceneElement.IsVisible`); the eye style now binds `IsVisible` and hidden rows dim to 45%. 3. **Duplicate naming:** shared `NextSourceName(scene, baseName)` → `Image`, `Image2`, `Image3`… (no space), next free number derived from actual names so deletions never collide. Used by both `AddSource` and `AddReusedImage`. 4. **Social bar:** `MaxWidth=200` + `CharacterEllipsis` removed from BOTH `SocialBarRenderer.cs` and the preview DataTemplate — full validated handle renders. 5. **Panels:** left 220 / right 300 fixed widths are deliberate — panels never re-layout on resize; the preview absorbs it. No change. 6. **Focus-loss capture lag:** recorded in `ai.md` as a known OS limit (DWM/WGC throttling when unfocused + GPU readback contention + the `_framePending` / `DispatcherPriority.Render` gates). NOT an in-app throttle; deferred by user decision. - **Test infra change:** the two real-WPF-App tests (round-clip + new source-naming) now share `RealAppHost` — a dedicated STA thread owning the single `App` — via the `RealApp` serial collection. WPF allows exactly one `Application` per AppDomain; never add a test that calls `new App()` directly again — marshal onto `RealAppHost` instead. - **Uncommitted:** `MainWindow.xaml` + `MainWindow.xaml.cs` (rows), `ViewModels/MainViewModel.cs` (commands + naming), `Models/SceneElement.cs` (+`IsEditing`), `Models/Scene.cs` (−`IsEditing`), `Services/Compositor/SocialBarRenderer.cs` (no truncation), `ytLive.Tests/SourceNamingTests.cs` (new), `ytLive.Tests/RealAppCollection.cs` (new), `ytLive.Tests/RoundClipInteractionTests.cs` (now uses the shared host), `TASKS.md` (TASK 7 ✅), `ai.md`, `ViewModels/index.md`, `HANDOFF`. - **Verified:** build 0 warnings / 0 errors; **170/170 tests pass** (169 + the naming test). - **Landmines:** - Never add another test that constructs `new App()` — use `RealAppHost.Run(...)`. - Never set a local `Canvas.SetTop` on the social bar — a local value permanently overrides `{Binding SocialBarTop}` (the `ClearValue` lesson from 5.5). - `AudioMixer` meter `Push` is unconditional **by design now**: `OnMicSample`/ `OnLoopbackSample` compute the level first, then raise the event — a `?.Invoke(meter.Push(...))` short-circuit skipped the meter update when nothing was subscribed (found by `RestartMic_ResetsLevel`, fixed). - `MicConnected` comes from the source `Started` event, raised right after `StartRecording()` succeeds — tests must `MarkStarted()` the fake source before asserting connection state. - The mic dot is red until a resource connects (see contract below) — green only after `Started`, yellow on `Failed`. - Zero mic devices at startup = red dot AND the mixer is never started, so loopback + the game bar can't run either (no capture at all) — acceptable. - The game detector is polled on the UI thread via a 250ms `DispatcherTimer`; `OnGameAudioPollTick` wraps `Poll()` in try/catch + `AppLog`. - The pump reads the active scene on a background thread while the UI can still edit it — a concurrent-mutation exception is contained (logged + `Failed` + the pump stops), not a crash. - `StopAsync` must stop the encoder (closes stdin) **before** awaiting the pump loop — closing stdin unblocks a write stuck on pipe backpressure; the reverse order deadlocks. - Tests never instantiate `MainViewModel` directly except via a real `MainWindow` on the `RealAppHost` STA thread (round-clip + naming), which never go live. - Sandbox can't reach outbound HTTPS — `HttpSocialValidator` stub-handler tests only, never the real instance. - **Mic status contract (creator's rule, verified — do NOT "fix"):** the status dot is **red until a mic resource is actually connected**. `MicStatus` starts `NotConnected` (red); it goes green ONLY when the mixer's `MicConnected` fires, which comes strictly from the mic source's `Started` event raised after `StartRecording()` succeeds. Zero devices at startup → stays red and the mixer is never started; capture failure → yellow. - **Next step:** commit + push this TASK 7 batch (one commit). Then the remaining TASK 4 requirement is **ship step 7 — one-click go live + private-only enforcement** (honor the dialog's chosen visibility / enforce `privacyStatus = "private"`; also fixes the REC sign's private state — see round-3 note). Also queued: task 21 (logo + About hub), task 22 (voice filters). Nothing else queued — do not expand the task queue on your own. Optional, not queued: rewriting the healed entry's `ProfileUrl` to `https://mastodon.llamachile.tube/@gramps` (user must say the word). - **Secret/DB/port facts live:** OAuth client id/secret in `Helpers/OAuthCredentials.cs`; OAuth session token in `Helpers/TokenStore.cs` (DPAPI → `%APPDATA%\ytLlive\ytLlive.auth`); layout DB `%APPDATA%\ytLlive\ytLlive.db` (schema v8; `SocialEntry.Software` column is a column-presence migration like the others, no version bump); OAuth callback `http://localhost:8765/oauth2/callback`; crash log `%APPDATA%\ytLlive\startup.log`.