Files
ytLlive/HANDOFF.md
T

7.1 KiB
Raw Blame History

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-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 \\llamavaultAssets/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 PrivateGoLiveViewModel.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 privateYouTubeStreamService.CreateBroadcast always sends privacyStatus="private"; ctor gained HttpClient? http = null seam for tests.
    3. Wired into go-liveBeginGoLive 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 testytLive.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.