Files
ytLlive/HANDOFF.md
T

5.4 KiB

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. 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.