fix(stream): health poll crashed on every start — parse the real healthStatus object shape
startup.log 2026-09-22 (via the user's run of the new build): every session
start logged 'Stream health poll failed: The requested operation requires an
element of type String, but the target element has type Object'.
Root cause: GetStreamHealthAsync did status.healthStatus.GetString(), but the
real API nests it as status.healthStatus = {status, lastUpdateTimeSeconds,
configurationIssues[]} — an OBJECT, per the liveStreams reference
https://developers.google.com/youtube/v3/live/docs/liveStreams (checked the
docs before fixing, per derivative-work rule). Our flat-string fixture was the
wrong assumption since TASK 9; the report-by-exception health banner had been
silently dead.
Fix: read the nested healthStatus.status + nested configurationIssues[], tolerating
the legacy flat-string shape so nothing else breaks. Tests flipped to the real
object shape (the Good Dog for this change). Full suite 315/315, build 0 warnings.
Also recorded in MyMistakes.md (API-shape recipe) and ai.md/Services index. End-of-session
transition(complete) 403 invalidTransition (enableAutoStop fallback) observed on all three
2026-09-22 stops — separate racy-design issue, carried, not in this change.
This commit is contained in:
+22
-19
@@ -1,30 +1,18 @@
|
||||
# HANDOFF — 2026-09-22 (TASK 42 top bar redesign implemented; commit + full-suite rerun owed)
|
||||
# HANDOFF — 2026-09-22 (TASK 42 committed; health-poll parse fix in flight)
|
||||
|
||||
## Branch / Commit State
|
||||
|
||||
`main` HEAD = **`bb5dcb4` — feat(stream): TASK 41 Test Stream mode …** (TASK 41 committed).
|
||||
Pushed state at `197ee81`. **Working tree DIRTY — TASK 42 implementation done, not yet committed**
|
||||
(docs updated in this same pass; next step is scope-check + build + full tests + one commit):
|
||||
`main` HEAD = **`e69db4d` — feat(ui): TASK 42 top bar redesign …** (committed).
|
||||
Pushed state at `197ee81` (verified from the app-build the user ran after the commit). **Working
|
||||
tree DIRTY — health-poll parse bug fix, one small change (code + tests + docs):**
|
||||
|
||||
```
|
||||
M Controls/BottomBar.xaml(.cs) (gear removed)
|
||||
M Controls/TopBar.xaml(.cs) (rewrite + GearButton_Click)
|
||||
M Themes/Controls.xaml (SegmentToggle/SegmentLabel)
|
||||
M ViewModels/MainViewModel.Streaming.cs
|
||||
M ViewModels/MainViewModel.Account.cs
|
||||
M ViewModels/MainViewModel.Streaming.Operations.cs
|
||||
M ytLive.Tests/PillRadioTests.cs / TestStreamTests.cs
|
||||
?? ytLive.Tests/TopBarModeTests.cs (new Good Dog)
|
||||
M TASKS.md + TASKS/task-42-top-bar-redesign.md (new)
|
||||
M ai.md, ViewModels/index.md, Controls/index.md, TASKS/task-40-app-settings-round.md
|
||||
M Services/YouTubeStreamService.cs (parse fix)
|
||||
M ytLive.Tests/YouTubeStreamServiceTests.cs (fixtures flipped to REAL api shape)
|
||||
M ai.md, Services/index.md, MyMistakes.md
|
||||
M HANDOFF.md (this rewrite)
|
||||
```
|
||||
|
||||
Build impact: main + tests build clean, **0 warnings**; targeted suite **6/6 pass**; full-suite run
|
||||
**314/315 pass** — the single abort is the known environment-dependent `RealMouseDrag` test (Path of
|
||||
Exile 2 running, physical-mouse injection no-ops; see ⚠️ below and rerun with the game closed for a
|
||||
clean 315/315).
|
||||
|
||||
## What shipped — TASK 42: top bar redesign (2026-09-22)
|
||||
|
||||
Full record: **`TASKS/task-42-top-bar-redesign.md`**. Creator directive: "forget this one dog plan
|
||||
@@ -53,6 +41,21 @@ changing + running reality values. Also folded in: TASK 41's latent **Test pipel
|
||||
`BeginTestStream` now arms `OnAirPillOn` explicitly (unarmed → encoder booted with zero outputs →
|
||||
"At least one output is required" → forced stop cascade). The TestStreamTests gate updated to match.
|
||||
|
||||
## In flight — health-poll parse fix (2026-09-22, from startup.log)
|
||||
|
||||
The user ran the new build and the app's `startup.log` showed `Stream health poll failed: The
|
||||
requested operation requires an element of type 'String', but the target element has type 'Object'.`
|
||||
on EVERY session start (2/2 test sessions). Root cause: `YouTubeStreamService.GetStreamHealthAsync`
|
||||
called `healthStatus.GetString()` but the real API nests `status.healthStatus = {status,
|
||||
lastUpdateTimeSeconds, configurationIssues[]}` — an OBJECT, not a string (docs:
|
||||
https://developers.google.com/youtube/v3/live/docs/liveStreams). Our own flat-string fixture was the
|
||||
wrong assumption from day one; the report-by-exception health banner had been silently dead. Fix in
|
||||
the dirty tree reads the nested `.status` and nested `configurationIssues[]`, tolerating the old flat
|
||||
shape; fixtures flipped to the real shape (the Good Dog). ALSO logged: end-of-session
|
||||
`transition(complete)` 403 `invalidTransition` → enableAutoStop fallback hit all three 2026-09-22
|
||||
stops (17:09 crash + both tests) — known racy design (transition AFTER encoder EOF), NOT in this fix's
|
||||
scope, carried.
|
||||
|
||||
## ⚠️ Around the task
|
||||
|
||||
- **Full-suite run today: 314/315** — the one abort is the pre-existing
|
||||
|
||||
Reference in New Issue
Block a user