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 =cc2d1efas 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 incc2d1efand is documented in ai.md; not duplicated here.
This commit is contained in:
+44
-15
@@ -1,9 +1,10 @@
|
|||||||
# HANDOFF — current state
|
# HANDOFF — current state
|
||||||
|
|
||||||
**Branch:** `main` (pre-1.0, no feature branches — creator ruling 2026-08-24).
|
**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
|
**Pushed 2026-10-04:** `origin/main` = `cc2d1ef`, working tree clean. That push carried
|
||||||
line below used to under-report the unpushed work by 7 commits, which is exactly the failure
|
13 commits (the 2026-09-27 → 10-02 backlog plus two units from today). The stale-push-state
|
||||||
`MyMistakes.md` warns about: a stale handoff makes the reader's next action wrong).
|
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
|
## 🚨 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
|
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.
|
**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()`
|
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
|
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
|
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
|
(`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.
|
delete path** — the creator clears each one by hand in Studio.
|
||||||
|
|
||||||
**⛔ The one diagnostic question, worth answering before anything else queued:** during a real
|
**✅ DIAGNOSTIC ANSWERED 2026-10-04 — ffmpeg reaches YouTube; the broadcast never goes LIVE.**
|
||||||
test stream, **does ffmpeg reach `a.rtmp.youtube.com`, and does the broadcast reach LIVE?**
|
One test-mode push, read from `startup.log`. The three steps, resolved:
|
||||||
That single observation localises the failure to one of three steps. Do not go hunting beyond
|
1. `new MediaFoundationReader`/RTMP path — **WORKS.** ffmpeg opened
|
||||||
it until it is answered.
|
`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
|
**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
|
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
|
## 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"
|
- **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
|
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*
|
`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
|
## Test state
|
||||||
|
|
||||||
**380/380, 0 warnings, re-verified 2026-09-28 on a clean test-project build** (the count is 380,
|
**381/381, 0 warnings, re-verified 2026-10-04 on a clean test-project build** (380 + the
|
||||||
not the 379 recorded earlier — the `force-ssl` scope test added one). Build the **test** project,
|
TRAX probe test added today). Build the **test** project, not just the app project, or VSTest
|
||||||
not just the app project, or VSTest runs a stale DLL.
|
runs a stale DLL.
|
||||||
|
|
||||||
**⚠️ New flake, do not chase it as a regression:** on the *first* full-suite run,
|
**⚠️ New flake, do not chase it as a regression:** on the *first* full-suite run,
|
||||||
`AudioPipelineTests.MasterLimiter_CapsTheLiveMix_OnThePipe` failed with `Expected 0.891,
|
`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
|
## Next
|
||||||
|
|
||||||
1. **Answer the RTMP diagnostic — an observation, not a build** (see the OPEN entry above).
|
1. **Log the broadcast status during a stream, then one 60-second test** — the RTMP
|
||||||
One test stream, then read `startup.log` for whether ffmpeg reached YouTube and whether the
|
diagnostic came back "ffmpeg fine, broadcast never goes live", which is a *narrower*
|
||||||
broadcast went LIVE. **Cheap, and it gates a queued task**, which is why it sorts first. It
|
question than the one item 1 used to ask. One code change (reuse the health poll timer)
|
||||||
does not reorder anything below — the packaging unit is still the next *code* unit.
|
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.
|
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
|
Full trust, `webcam`/`microphone`, English only; Velopack deleted. Add the
|
||||||
`DefaultRecordFolder()` comment in the same unit, and the WebView2 framework dependency +
|
`DefaultRecordFolder()` comment in the same unit, and the WebView2 framework dependency +
|
||||||
|
|||||||
Reference in New Issue
Block a user