5.8 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-14)
-
Branch:
main, in sync withorigin/main. -
TASK 8 — meter scaling amplification: SHIPPED + pushed (
0b71b03).AudioLevelMeter.ToDisplayadds +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;× MicVolumeuntouched. -
TASK 4 ship step 7 — one-click go live + private-only enforcement: SHIPPED (this session; the final open TASK 4 requirement). Double-enforced privacy:
- Dialog locked to Private —
GoLiveViewModel.Visibilityis a get-only"Private", the visibility ComboBox is gone (replaced by a "Streams always start Private" note); settings' dead "Default Visibility" dropdown +MainViewModel.Visibilities/DefaultStreamVisibilityremoved. - Service forces private —
YouTubeStreamService.CreateBroadcastalways sendsprivacyStatus="private"; ctor gainedHttpClient? http = nullseam for tests. - Wired into go-live —
BeginGoLivefiresCreateBroadcastAsync(stores_currentBroadcastIdfor TASK 5's bind/transition; failure →StreamStatus.Errorvia AppLog, never a crash) +_framePump.StartAsync();StopStreamclears_currentBroadcastId. - PRIVATE badge — dark-red bordered, next to REC in the top bar,
Visibility="{Binding IsLivePrivate}"(MainWindow.xaml ~110). - Integration test —
ytLive.Tests/YouTubeStreamServiceTests.cs: the broadcast-insert request must carry"privacyStatus":"private"(RecordingHandler seam) + a no-session → null guard test.
- Dialog locked to Private —
-
Verified: build 0 warnings / 0 errors; 173/173 tests pass (171 + the 2 stream-service tests).
-
Uncommitted (this session's ship step 7 batch):
GoLiveWindow.xaml,ViewModels/GoLiveViewModel.cs,ViewModels/MainViewModel.cs,Services/YouTubeStreamService.cs,MainWindow.xaml,ytLive.Tests/YouTubeStreamServiceTests.cs(new),TASKS.md,ai.md,ViewModels/index.md,Services/index.md,HANDOFF.md. Commit + push before continuing. -
Next step: commit + push ship step 7, then TASK 5 — reusable
variablestream (create once per channel, cache ingestion URL, bind to broadcast, feed_rtmpUrlProviderso the pump actually pushes —_currentBroadcastIdis already stashed for it). 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'sProfileUrltohttps://mastodon.llamachile.tube/@gramps(user must say the word). -
Landmines:
- Never add another test that constructs
new App()— useRealAppHost.Run(...)(shared STA host for the one WPF App per AppDomain; round-clip + source-naming tests). - Never set a local
Canvas.SetTopon the social bar — a local value permanently overrides{Binding SocialBarTop}(theClearValuelesson from 5.5). AudioMixermeterPushis unconditional by design now:OnMicSample/OnLoopbackSamplecompute the level first, then raise the event — a?.Invoke(meter.Push(...))short-circuit skipped the meter update when nothing was subscribed (found byRestartMic_ResetsLevel, fixed).MicConnectedcomes from the sourceStartedevent, raised right afterStartRecording()succeeds — tests mustMarkStarted()the fake source before asserting connection state.- The mic dot is red until a resource connects (see contract below) — green
only after
Started, yellow onFailed. - 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;OnGameAudioPollTickwrapsPoll()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. StopAsyncmust 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
MainViewModeldirectly except via a realMainWindowon theRealAppHostSTA thread (round-clip + naming), which never go live. - Sandbox can't reach outbound HTTPS —
HttpSocialValidatorstub-handler tests only, never the real instance.
- Never add another test that constructs
-
Mic status contract (creator's rule, verified — do NOT "fix"): the status dot is red until a mic resource is actually connected.
MicStatusstartsNotConnected(red); it goes green ONLY when the mixer'sMicConnectedfires, which comes strictly from the mic source'sStartedevent raised afterStartRecording()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 inHelpers/TokenStore.cs(DPAPI →%APPDATA%\ytLlive\ytLlive.auth); layout DB%APPDATA%\ytLlive\ytLlive.db(schema v8;SocialEntry.Softwarecolumn is a column-presence migration like the others, no version bump); OAuth callbackhttp://localhost:8765/oauth2/callback; crash log%APPDATA%\ytLlive\startup.log.