docs: handoff answers the RTMP diagnostic and records today's two units

The handoff asked for the RTMP diagnostic as item 1 and claimed the next code
unit was packaging. Both are now wrong, and per the map's own rule a stale
handoff is worse than none because the reader trusts it.

1. DIAGNOSTIC ANSWERED, and it narrowed the question rather than closing it.
   ffmpeg reaches YouTube — rtmp://a.rtmp.youtube.com/live2/..., 7.4 MB video
   plus 46 KB audio muxed, no socket error. The broadcast never leaves `ready`:
   enableAutoStart=true was sent, yet close-out refused `complete` with 403
   invalidTransition, which is only legal from `live`. Two things stay honestly
   unknown — the push was only 8s, and the app never polls broadcast status
   during a stream (only stream health), so the log cannot show whether or when
   it flipped. Next step is one log line plus one 60-second test.

2. Packaging is DEFERRED, not next. Creator ruling 2026-10-04: still in active
   development, so ship-time work waits. Item 1 of "Next" said the opposite.

3. Push state: origin/main = cc2d1ef as of 2026-10-04, tree clean. Stale push
   state has now bitten twice here, so the line now tells the next session to
   verify with rev-list instead of believing the file.

4. Test count 381, not 380.

5. New landmine: the frame pump logged 86 stalls per 5s (142 lines in an
   8-second window) while stats still read 301/300 frames and 0 dropped. Those
   two facts contradict each other; recorded as a measurement to take, not a
   bug to fix from the log.

Startup stall (TRAX / unreachable NAS) shipped in cc2d1ef and is documented in
ai.md; not duplicated here.
This commit is contained in:
2026-10-04 09:37:32 -07:00
parent cc2d1ef622
commit 048cab79f8
+44 -15
View File
@@ -1,9 +1,10 @@
# HANDOFF — current state
**Branch:** `main` (pre-1.0, no feature branches — creator ruling 2026-08-24).
**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).
**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.**
## 🚨 FIXED 2026-09-27 — "Change Account" no longer signs you out before the browser opens
@@ -160,8 +161,10 @@ Two gaps remain that bundling cannot fix, and they are the next real risks: the
runtime** is a machine prerequisite (item 2's manifest dependency + a graceful-failure path), and
**Velopack's updater downloads and executes**, so its teardown in step 3 is a compliance action.
### The next code unit: the packaging project + `Package.appxmanifest` (TASK 48 items 2–3)
### Deferred, not next: the packaging project + `Package.appxmanifest` (TASK 48 items 2–3)
**Creator ruling 2026-10-04: still in active development, so ship-time work waits and
queued features come first.** The unit is unchanged and ready when it is wanted:
Full trust, `webcam`/`microphone`, English only; Velopack deleted. Add the `DefaultRecordFolder()`
comment in the same unit (the mediumIL invariant below becomes load-bearing the moment the manifest
lands). Full-trust writes under a real package identity are still **unverified** — confirm on a
@@ -210,10 +213,29 @@ 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.
**✅ DIAGNOSTIC ANSWERED 2026-10-04 — ffmpeg reaches YouTube; the broadcast never goes LIVE.**
One test-mode push, read from `startup.log`. The three steps, resolved:
1. `new MediaFoundationReader`/RTMP path — **WORKS.** ffmpeg opened
`rtmp://a.rtmp.youtube.com/live2/4pew-…`, muxed **7.4 MB video + 46 KB audio**, and
finalised the FLV with no socket error. Step 2 is fine.
2. **The broadcast stays `ready` — this is the break.** `enableAutoStart = true` *is* sent
on insert (`Services/YouTubeStreamService.cs:73`), yet at close-out YouTube refused
`transition=complete` with **403 `Invalid transition`** — which is only legal from `live`.
So YouTube never flipped `ready → live`.
3. Never reached (nothing to archive because nothing went live).
**Two unknowns, and the honest state of each:**
- **The push ran only 8 seconds** (08:48:23.9 → 08:48:32.8). YouTube may simply need longer
to accept and validate the ingest before it auto-starts. Untested — do not assume.
- **The app cannot see this either way.** During a stream it polls **stream** health
(`liveStreams`) and never the **broadcast** status; `GetLifeCycleStatusAsync` is called
*only* from the end path (`YouTubeStreamService.cs:146`). So the log contains no evidence
either way, and `EndBroadcastAsync` skips only on `complete`/`revoked`, meaning it tries
`complete` against a `ready` broadcast and earns the 403.
**⇒ Next step, small and cheap:** log the broadcast's `lifeCycleStatus` while streaming
(reuse the existing health poll timer — no new loop), then run **one 60-second** test. That
single run answers it. Do not go hunting beyond it until it has.
**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
@@ -225,6 +247,11 @@ Detail and the open 11.12 re-check: [`TASKS/task-50-publish-recording.md`](TASKS
## Landmines
- **Frame pump jitter, unquantified (2026-10-04).** The same test stream logged **86 stalls
per 5s** (`FramePump stall: iteration 40–50ms` against a 17ms budget; 142 such lines in an
8-second window) while `FramePump stats` still read 301/300 frames, 0 dropped. Nominal 60fps
with zero drops *and* repeated 3× overruns is a contradiction worth one measurement, not a
guess. Do not "fix" it from the log alone.
- **Stale fact inside `TASKS.md` (left alone, flagged here per the Scope Lock).** The "1.0 gates"
section asserts "**TASK 36 is now shipped**", but the catalog row 36 reads **☐ Queued** and
`task-36-gold-pass.md` still shows items 1–6 unchecked. The line most likely means *item 2*
@@ -247,9 +274,9 @@ Detail and the open 11.12 re-check: [`TASKS/task-50-publish-recording.md`](TASKS
## Test state
**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.
**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.
**⚠️ New flake, do not chase it as a regression:** on the *first* full-suite run,
`AudioPipelineTests.MasterLimiter_CapsTheLiveMix_OnThePipe` failed with `Expected 0.891,
@@ -270,10 +297,12 @@ whole-suite scheduling artifact of the same family as the `RealAppHost` STA land
## Next
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.
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.
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 +