diff --git a/HANDOFF.md b/HANDOFF.md index ea1e696..f1010b2 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -1,8 +1,9 @@ # HANDOFF — current state **Branch:** `main` (pre-1.0, no feature branches — creator ruling 2026-08-24). -**Last pushed:** `e7cded6` (pricing/Store fee docs). **Local, unpushed:** `536676f` (recording -filename ms) and the Change Account fix in this unit — ask before pushing. +**Caught up 2026-09-28:** `main` is pushed to `origin/main` (was 9 commits ahead — the handoff +line below used to under-report the unpushed work by 7 commits, which is exactly the failure +`MyMistakes.md` warns about: a stale handoff makes the reader's next action wrong). ## 🚨 FIXED 2026-09-27 — "Change Account" no longer signs you out before the browser opens @@ -143,7 +144,8 @@ gitignored `ffmpeg/` from a **SHA-256-verified** pinned month-end BtbN artifact; copies it to output *and publish* and **fails the build** if it's missing; `FfmpegLocator` lost its downloader, its zip extraction and the `%APPDATA%\ytLlive\tools` cache, and now resolves **bundle → PATH** with a loud, actionable failure. The pin that 404'd is gone, so the -2026-09-01 failure class cannot recur. Suite **379/379**, 0 warnings; 16 locator facts including an +2026-09-01 failure class cannot recur. Suite **379/379 at that point** (380 now — see Test +state); 16 locator facts including an integration test that **executes the bundled binary** (which is what proves the sibling DLLs resolve). `THIRD-PARTY-NOTICES.txt` corrected — it still named the *stale* tag `autobuild-2026-08-09-13-03`, i.e. the one that 404'd. @@ -185,6 +187,42 @@ Carried over from the research unit, still open: the 11.12 certification answer. No chat history, moderation log, analytics, or crash payload may be added without re-arguing 11.12 first. +## 🚨 OPEN 2026-09-28 — the RTMP push never lands: recordings reach YouTube as EMPTY placeholders + +**This is a live bug, not a queued feature**, and it reframes a complaint the map previously +treated as closed. It was found on 2026-09-28 while scoping TASK 50, and the handoff had no +entry for it at all — corrected here. + +**What the creator observed:** the channel carries **20+ private videos, all content-less +placeholders** (creator-inspected, 2026-09-28). This is the real explanation of the +2026-09-26 report "I still cannot get private test recordings saved" — it was never true that +the app could not *find* an archived VOD. **No video content is ever produced on the channel.** + +**Mechanism (verified against the code AND the channel):** `liveBroadcasts.insert` succeeds and +creates the placeholder; everything after it is what fails. Content only exists if all three of +these land, and at least one does not: +1. broadcast reaches **LIVE** via `liveBroadcasts/transition`, +2. ffmpeg actually pushes RTMP to the bound stream key, +3. the broadcast ends and YouTube transcodes it into a VOD. + +`enableAutomaticArchiving` is **never set**, so YouTube's `true` default applies — the archiving +route exists but has nothing to archive. Broadcasts are inserted `private` +(`Services/YouTubeStreamService.cs:49`), so the orphans are not public, and the app has **no +delete path** — the creator clears each one by hand in Studio. + +**⛔ The one diagnostic question, worth answering before anything else queued:** during a real +test stream, **does ffmpeg reach `a.rtmp.youtube.com`, and does the broadcast reach LIVE?** +That single observation localises the failure to one of three steps. Do not go hunting beyond +it until it is answered. + +**Sequencing constraint — do not flip the flag early.** `enableAutomaticArchiving: false` is the +correct end state (TASK 50 will upload the local file deliberately), but archiving is +**currently the only route a recording takes to YouTube** — flipping it before TASK 50 ships +would leave test streams with nothing at all and re-create the 2026-09-26 complaint in a worse +form. Ship the upload, flip the flag in the same task, never before. + +Detail and the open 11.12 re-check: [`TASKS/task-50-publish-recording.md`](TASKS/task-50-publish-recording.md). + ## Landmines - **Stale fact inside `TASKS.md` (left alone, flagged here per the Scope Lock).** The "1.0 gates" @@ -209,9 +247,18 @@ Carried over from the research unit, still open: ## Test state -**379/379, 0 warnings, as of the ffmpeg-bundling unit (2026-09-28).** Build the **test** project, +**380/380, 0 warnings, re-verified 2026-09-28 on a clean test-project build** (the count is 380, +not the 379 recorded earlier — the `force-ssl` scope test added one). Build the **test** project, not just the app project, or VSTest runs a stale DLL. +**⚠️ New flake, do not chase it as a regression:** on the *first* full-suite run, +`AudioPipelineTests.MasterLimiter_CapsTheLiveMix_OnThePipe` failed with `Expected 0.891, +Actual 0` — a **zero**, not a slightly-off value, which is the signature of the pipe not being +fed yet rather than the limiter misbehaving. It passed 27/27 as a class run and 380/380 on an +immediate full-suite re-run. It reads the live mix **off the named pipe**, so it is a +whole-suite scheduling artifact of the same family as the `RealAppHost` STA landmine below — +**if it ever goes red, re-run before believing it.** + ## Uncommitted / untracked - `ffmpeg/` — the 9 bundled binaries (~135 MB), **gitignored by design**. Populated by @@ -223,29 +270,39 @@ not just the app project, or VSTest runs a stale DLL. ## Next -1. **The packaging project + `Package.appxmanifest`** (TASK 48 items 2–3) — the next code unit. +1. **Answer the RTMP diagnostic — an observation, not a build** (see the OPEN entry above). + One test stream, then read `startup.log` for whether ffmpeg reached YouTube and whether the + broadcast went LIVE. **Cheap, and it gates a queued task**, which is why it sorts first. It + does not reorder anything below — the packaging unit is still the next *code* unit. +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 + graceful-failure path. -2. **Declare the IAP products in Partner Center** — the price is **settled** ($10/mo, $400 +3. **TASK 50 — one-button "Publish this video"** (`TASKS/task-50-publish-recording.md`). Queued + behind the Store submission by its own precedence note ("MSIX first, publish second — unless + the creator reverses that"). Scoping is done; the build is not. ⛔ Do **not** flip + `enableAutomaticArchiving` until it ships. It also carries an **open 11.12 re-check**: a + publish feature makes the app *push* creator content to a third party, so the IARC answers + must not go to certification describing an app that cannot publish. +4. **Declare the IAP products in Partner Center** — the price is **settled** ($10/mo, $400 lifetime, no annual, 15% verified), so this is unblocked. **Blocks:** the Store listing and the `OverlayHost.xaml` copy. ⛔ The Individual-vs-Company account question is still unanswered — get it right before enrolling. -3. **Polar teardown** (TASK 48 item 0) — `PolarLicenseService`, `PolarLicense`, +5. **Polar teardown** (TASK 48 item 0) — `PolarLicenseService`, `PolarLicense`, `MainViewModel.License.cs`, the `OverlayHost.xaml` string, the `csproj`/`App.xaml.cs` Velopack sites. `IsPremium` ← Store entitlement. **Do this as one unit** — a half-torn-down licensing path is worse than either end state. -4. **Vertical recording verification** — the compositor tier is proven by +6. **Vertical recording verification** — the compositor tier is proven by `Render_VerticalTier_Outputs_1080x1920_From_The_Center_Crop`; the *record* path has never been run. `FramePump.cs:645` flags off-size tiers as a known follow-up. -5. **WACK + certification notes + the privacy policy** (TASK 48 items 4–5) — the policy must +7. **WACK + certification notes + the privacy policy** (TASK 48 items 4–5) — the policy must state camera/mic is OS-gated, nothing is retained, and **nothing is fetched at runtime** (now literally true — the ffmpeg bundle is what makes that sentence defensible). -6. **Post-session efficacy report** — roll up `CurrentHealth` (dropped frames, duration, health +8. **Post-session efficacy report** — roll up `CurrentHealth` (dropped frames, duration, health message) when a stream or recording ends. `SessionTeardownTests` is the natural home. -7. **Measure whether the Windows camera toggle gates DShow** — gates all privacy-forward copy +9. **Measure whether the Windows camera toggle gates DShow** — gates all privacy-forward copy (`MARCOM.md` guard). Not a certification risk; a trust risk. -8. **TASK 36:212 stale "shipped" line** — one-line fix, needs a hand. +10. **TASK 36:212 stale "shipped" line** — one-line fix, needs a hand. **Dropped from the list** because the ruling made them moot: multi-instance's ffmpeg tools-dir race (item 1 deleted the tools dir entirely), `scripts/publish.sh` + the `LlamaCasty.exe` rename