# 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`. The audio UX follow-up (`9f9ed34`) and round 2 (`18abe42`) are **committed and pushed**. - **This session (round 3 — mic mute icon + REC sign):** 1. **Mic mute icon:** the mic bar gained a **microphone glyph** (same 16px style as the speaker, white → red + slash when muted, `ToolTip=MicMuteText`) **between the meter and the speaker** — both mutes adjacent with spacing between the icons; click reuses the same `MicSpeaker_MouseLeftButtonUp` handler → `ToggleMicMuteCommand`. No VM/code-behind change. 2. **REC sign (top center):** the old LIVE badge (hidden when offline) became an **always-visible REC chip** — dark gray dot (#555) + dim "REC" (#888) offline, **bright red (#e94560)** + "REC" + elapsed while live, **darker red (#8f1f1f)** when live with a **private** stream. Driven by new VM props `RecDotBrush`/`RecTextBrush`/`RecDotOpacity`/`IsLivePrivate` (notified from the `StreamStatus` and `StreamVisibility` setters), privacy read off the **dialog's chosen visibility** (`StreamVisibility == "Private"`) — the stream service still hardcodes `privacyStatus = "public"`, so the private-REC state only lights once that's honored (TASK 4 ship step 7). The dot pulses while live; `LiveIndicatorVisible` and `LivePulseOpacity` were removed. 3. **Voice filters queued as task 22** — bass boost, treble, noise suppression, compressor on the mic input channel, KISS, always on (before the meter/encoder mix). - **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. Green must never be raised earlier (e.g. on loopback start or on `Start()` being called). - **Uncommitted:** this round-3 work — `ViewModels/MainViewModel.cs` (REC props, `_recDotPulse`, StreamVisibility/StreamStatus notifications, `LiveIndicatorVisible`/ `LivePulseOpacity` removed), `MainWindow.xaml` (REC chip + mic mute icon), `TASKS.md` (task 22 + round-3 audio note), `ai.md`, `ViewModels/index.md`, `HANDOFF`. - **Verified:** pending (build + full test run right before commit). - **Landmines:** - 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 above) — 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 the round-clip integration test (a real `MainWindow`), which never goes live — keep it that way. - Sandbox can't reach outbound HTTPS — `HttpSocialValidator` stub-handler tests only, never the real instance. - **Next step:** commit + push round 3 (one commit). Then TASK 4 ship step 6 — health stats: bind `FramePump.HealthUpdated` (bitrate/FPS/duration) into the bottom bar. 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`.