diff --git a/HANDOFF.md b/HANDOFF.md index 792145a..72150ab 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -1,10 +1,44 @@ # HANDOFF — current state **Branch:** `main` (pre-1.0, no feature branches — creator ruling 2026-08-24). -**Pushed 2026-10-04:** `origin/main` = `cc2d1ef`, working tree clean. That push carried -13 commits (the 2026-09-27 → 10-02 backlog plus two units from today). The stale-push-state -failure `MyMistakes.md` warns about has now bitten twice, so the rule stands: **check -`git rev-list --count origin/main..main` before trusting any line here about push state.** +**Pushed 2026-10-04:** `origin/main` = `048cab7`. **NOT PUSHED since — local `main` is 5 commits +ahead and the tree is clean.** The stale-push-state failure `MyMistakes.md` warns about has now bitten +twice, so the rule stands: **check `git rev-list --count origin/main..main` before trusting any line +here about push state.** + +Unpushed: `5ad0106` broadcast diagnostic → `74da99c` + `0fb2f9c` privacy/Test rulings → +`8fbc370` diagnostic parse fix → `07a088a` **the explicit-bind fix** → `509ef36` window placement. + +## 🚨 FIXED 2026-10-04 — broadcasts never went live because they were never BOUND + +**Root cause, proven by the diagnostic rather than inferred:** `contentDetails.boundStreamId` on +`liveBroadcasts.insert` **does not bind the broadcast.** The log line read +`lifeCycle=created privacy=private autoStart=true bound=NONE boundMatches=NO-BINDING | +streamStatus=active`. + +`created` is Google's *"incomplete settings"* state, so `enableAutoStart` had no bound stream to fire +from, and close-out 403'd `invalidTransition` because `created → complete` is not a legal edge. The +reason it survived a week: **a reusable stream accepts bytes for a broadcast that is not watching it**, +so a perfectly healthy 99 MB RTMP session is exactly what an unbound broadcast looks like. Google's +migration guide states the rule outright — *"a liveBroadcast must be bound to exactly one stream +before the live broadcast can actually start"* — and it was in the docs read during the original +design. + +Shipped `07a088a`: `BindBroadcastAsync` → `POST liveBroadcasts/bind?part=id&id&streamId` (no body), +called right after `CreateBroadcast` and before the pump; failure is fatal to the session because an +unbound broadcast can never go live. `boundStreamId` and `CreateBroadcast`'s `streamId` parameter both +removed. The old test asserting insert-time binding **laundered a guess into a guarantee** and was +replaced. Also corrected the TASK 44 claim that `liveChatId` only appears once live — it is present +while lifecycle is `created`; that claim came from reading a sample's active-status guard as a spec. + +**⏭ NEXT STEP — needs the creator, one 60-second Test:** confirm `Broadcast bound:` appears and +lifecycle walks `created → ready → live`. If it binds but still won't auto-start, the *next* suspect +is an explicit `transition`, not the binding — do not re-open the binding question without log proof. + +**Coverage gap:** no automated test asserts `PrepareAndStartLiveAsync` actually *calls* bind — the +service method is tested in isolation, but the wiring in the ViewModel is not. Acceptable only +because the end-to-end symptom was the whole point of the diagnostic; revisit if the wiring is ever +touched again. ## 🚨 FIXED 2026-09-27 — "Change Account" no longer signs you out before the browser opens @@ -274,9 +308,10 @@ Detail and the open 11.12 re-check: [`TASKS/task-50-publish-recording.md`](TASKS ## Test state -**381/381, 0 warnings, re-verified 2026-10-04 on a clean test-project build** (380 + the -TRAX probe test added today). Build the **test** project, not just the app project, or VSTest -runs a stale DLL. +**395/395, 0 warnings, re-verified 2026-10-04 on a clean test-project build** (381 + 3 diagnostic +`FirstItem` cases + 1 window fact + 3 placement theory cases + 1 bind test, less 1 removed). +Build the **test** project, not just the app project, or VSTest runs a stale DLL. +**Launch exe for the creator's test run: `bin/Debug/net8.0-windows10.0.19041.0/ytLive.exe`.** **⚠️ New flake, do not chase it as a regression:** on the *first* full-suite run, `AudioPipelineTests.MasterLimiter_CapsTheLiveMix_OnThePipe` failed with `Expected 0.891, @@ -297,12 +332,15 @@ whole-suite scheduling artifact of the same family as the `RealAppHost` STA land ## Next -1. **Log the broadcast status during a stream, then one 60-second test** — the RTMP - diagnostic came back "ffmpeg fine, broadcast never goes live", which is a *narrower* - question than the one item 1 used to ask. One code change (reuse the health poll timer) - plus one long test closes it. It is the live bug, so it still sorts first; nothing below - reorders. Packaging is NOT next — the creator's ruling 2026-10-04: we are still in active - development, so ship-time work waits and queued features come first. +1. **~PUSH, then the creator's 60-second Test** — see the FIXED box above. Packaging is NOT next; + the creator's ruling 2026-10-04: still in active development, so ship-time work waits and queued + features come first. +2. **Frame-pump jitter (queued, unquantified):** ~86 stalls per 5 s in one log window, 142 in an + 8-second window, while stats reported 301/300 frames and **zero** drops. Measure before touching + anything — the counter and the missing-frame count currently disagree, and "fixing" the pump + without knowing which number is wrong risks making it worse. **Creator to-do, not yet queued: + long-run resource/consumption/recycling benchmarking** (how long the app stays healthy under full + burden) — record only, do not start it. 2. **The packaging project + `Package.appxmanifest`** (TASK 48 items 2–3) — the next code unit. Full trust, `webcam`/`microphone`, English only; Velopack deleted. Add the `DefaultRecordFolder()` comment in the same unit, and the WebView2 framework dependency +