# 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-14) - **Branch:** `main`, in sync with `origin/main`. - **TASK 21 — real logo + creator-hub About: SHIPPED** (this session). The About overlay is now the **creator hub**: the real logo ("llama fortnite superman logo" copied from `\\llamavault` → `Assets/llama-logo.png`, the creator's own art — no third-party license), plus hub links — **llama chile shop on YouTube** (`MainViewModel.ChannelUrl`, public now), **Mastodon** (`https://mastodon.llamachile.tube/@gramps`), **Buy me a coffee** (`https://buymeacoffee.com/llamachiley` — LIVE), and **Unlock Premium** (greyed "coming soon"; the itch.io product URL is a **tabled seam**, `MainViewModel.PremiumUrl` — the itch.io account was just created and needs a setup session later). **Licenses & legal** flips the About overlay to an in-app scrolling panel loading the shipped `THIRD-PARTY-NOTICES.txt` (`ShowLicenses()` reads from the executable dir on first open, graceful "not found" fallback — never the OS viewer); "← Back to About" (`BackToAbout_Click`) returns. Integration test (ONE): `AboutHubTests` drives the real window, asserting the hub opens, the link URLs are real, licensing loads the shipped notices text, and back returns to the hub. **174 tests passing, 0 warnings.** - **TASK 8 — meter scaling amplification:** SHIPPED + pushed (`0b71b03`). `AudioLevelMeter.ToDisplay` adds **+10 dB input amplification** before the −60..0 dBFS log map: speech peaks (~0.2 RMS) read ~0.93 (red) and normal speech (~0.05) ~0.73 (yellow) at maxed volume; ≤0.001 linear still reads 0 (never idles on background noise). One knob shared by the mic + game bars; `× MicVolume` untouched. - **TASK 4 ship step 7 — one-click go live + private-only enforcement: SHIPPED** (this session; the final open TASK 4 requirement). Double-enforced privacy: 1. **Dialog locked to Private** — `GoLiveViewModel.Visibility` is a get-only `"Private"`, the visibility ComboBox is gone (replaced by a "Streams always start Private" note); settings' dead "Default Visibility" dropdown + `MainViewModel.Visibilities`/`DefaultStreamVisibility` removed. 2. **Service forces private** — `YouTubeStreamService.CreateBroadcast` always sends `privacyStatus="private"`; ctor gained `HttpClient? http = null` seam for tests. 3. **Wired into go-live** — `BeginGoLive` fires `CreateBroadcastAsync` (stores `_currentBroadcastId` for TASK 5's bind/transition; failure → `StreamStatus.Error` via AppLog, never a crash) + `_framePump.StartAsync()`; `StopStream` clears `_currentBroadcastId`. 4. **PRIVATE badge** — dark-red bordered, next to REC in the top bar, `Visibility="{Binding IsLivePrivate}"` (MainWindow.xaml ~110). 5. **Integration test** — `ytLive.Tests/YouTubeStreamServiceTests.cs`: the broadcast-insert request must carry `"privacyStatus":"private"` (RecordingHandler seam) + a no-session → null guard test. - **Verified:** build 0 warnings / 0 errors; **174/174 tests pass** (173 + the new AboutHubTests). - **Uncommitted (this session's TASK 21 batch):** `MainWindow.xaml`, `ViewModels/MainViewModel.cs`, `MainWindow.xaml.cs`, `Assets/llama-logo.png` (replaced with the real logo), `ytLive.Tests/AboutHubTests.cs` (new), `TASKS.md`, `HANDOFF.md`. ai.md + ViewModels/index.md updates pending — **commit + push before continuing.** - **Next step:** commit + push TASK 21, then **TASK 5 — reusable `variable` stream** (create once per channel, cache ingestion URL, bind to broadcast, feed `_rtmpUrlProvider` so the pump actually pushes — `_currentBroadcastId` is already stashed for it). Also queued: **task 22 (voice filters)**, and **setting up the itch.io product page** (the creator just made the account; the premium-unlock URL then lands in `MainViewModel.PremiumUrl` and the About hub's "Unlock Premium" button lights up). 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). - **Landmines:** - Never add another test that constructs `new App()` — use `RealAppHost.Run(...)` (shared STA host for the one WPF App per AppDomain; round-clip + source-naming tests). - 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. - **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`.