Files
LlamaCasty/HANDOFF.md
T
gramps 94f015044a fix(stream): TEST-tab chat — resolve liveChatId from snippet, poll until the broadcast is live
The open creator report ('I still cannot post a chat message in the TEST tab',
feedback 'Chat polling couldn't start — Mock Chat Input is disabled') was a single
cause: the liveChatId never resolved. Two YouTube API facts:
1. The id lives in snippet.liveChatId — contentDetails has no such property
   (TASK 44 read part=contentDetails: could never resolve).
   https://developers.google.com/youtube/v3/live/docs/liveBroadcasts
2. It only exists once the broadcast is LIVE — the official sample lists
   broadcastStatus=active, and our fetch ran before the frame pump pushed RTMP
   (enableAutoStart flips ready→live). A ready-state list legitimately returns
   no id.
   https://github.com/youtube/api-samples/blob/master/java/src/main/java/com/google/api/services/samples/youtube/cmdline/live/GetLiveChatId.java

Fix: GetBroadcastLiveChatIdAsync reads part=snippet and polls with a bounded
retry (10x/2s); PrepareAndStartLiveAsync starts the frame pump FIRST, then
resolves the id. Chat stays non-fatal. Docs ai.md/TASKS.md/HANDOFF.md +
MyMistakes recipe updated same commit. TASK 44.

Good Dog: ONE integration test (GetBroadcastLiveChatIdAsync_Polls_Snippet_...
) drives a broadcast that gains its id mid-retry and asserts every request used
part=snippet. Gate: clean build 0 warnings, vstest 318/318.
2026-09-25 08:06:02 -07:00

69 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HANDOFF — 2026-09-25 (TASK 44 shipped: TEST-tab chat fix — liveChatId now resolves)
## Branch / Commit State
`main` HEAD = new commit for TASK 44 (TEST-tab chat fix); previous: TASK 43 commit (native
events & alerts), `ac6e67a` (end close-out). Repo is ~11 commits ahead of pushed `197ee81` —
**push is the creator's call** (sub-milestone decision, not per-commit).
**Working tree CLEAN after this unit's commit.**
## ⚠️ The unit that just shipped (the open TEST-tab chat report, diagnosed + fixed)
The HANDOFF-open creator report — *"I still cannot post a chat message in the TEST tab"* —
is **RESOLVED** (one cause, one scoped unit, TASK 44 in `TASKS/task-44-test-chat-fix.md`):
- **The feedback line** "Chat polling couldn't start — Mock Chat Input is disabled" is
`TestSessionViewModel.BeginTest` running with a **null liveChatId**.
- **Root cause (two API facts, cited in commit + MyMistakes):** (1) `liveChatId` lives in
**`snippet.liveChatId`** — `contentDetails` has no such property, and the old code read
`part=contentDetails` (can NEVER resolve); (2) YouTube only populates it once the broadcast
is **live** (official `GetLiveChatId.java` lists `broadcastStatus=active`), and the fetch
ran before the frame pump pushed RTMP (enableAutoStart flips ready→live).
- **Fix:** `GetBroadcastLiveChatIdAsync(broadcastId, maxAttempts=10, delayMs=2000)` now reads
`part=snippet` and polls with a bounded retry; `PrepareAndStartLiveAsync` starts the frame
pump FIRST, then resolves the id. Chat stays non-fatal. TEST drawer wiring unchanged
(`BeginTest` opens the dock once the id resolves → Mock Chat Input becomes sendable).
**Good Dog:** ONE integration test in `YouTubeStreamServiceTests.cs`
(`GetBroadcastLiveChatIdAsync_Polls_Snippet_Until_Id_Appears`) — a fake broadcast that starts
without a liveChatId and gains it on a later poll; asserts the retry resolves it, polled ≥3x,
and every request asked for snippet (never contentDetails). **Gate: clean build 0 warnings,
full vstest 318/318 passed** (the LayerReorder real-mouse-drag test passed this run too).
## Follow-ups queued (NOT done in this unit)
- **TASK 3 item 20 persistence half** — the canonical `RewardEvents` SQLite table +
`superChatEvents.list` (30-day) backfill + session-report rollup (events still parse to
`ChatMessage` in memory only).
- TASK 3 item 16 (Text source) still open; TASK 40 units A/C/D queued; TASK 32–36 queued.
## Around the task (carried facts)
- RealMouseDrag tests no-op while a game/fullscreen window steals the mouse (POE 2 seen
2026-09-22) — close games before full-suite runs. AudioPipeline timing flake similar.
- Test-env trap: saved OAuth session loads synchronously → force `vm.IsConnected` in signed-in tests.
- `subscriberCount` YPP slice 2 needs re-consent — do not merge with other units. `$99/yr` Polar
must become one-time before launch. `MARCOM.md`/`MONETIZATION.md` gitignored — never commit.
- Latent bug the YPP 403 masked: statistics are JSON **strings** — always the ValueKind-first
`ReadInt64` (MyMistakes recipe), never `GetInt64`.
- **API fact (TASK 44):** a liveChatId fetch at insert time (lifecycleStatus `ready`) returns
nothing by design — missing liveChatId ≈ "broadcast not live yet", not an auth failure,
until ~20s post push. Debug with that lens.
- Every committed change needs a **close + relaunch** of the running app to be seen — running
builds are live; verify.sh can't run while the exe is locked.
## Next step
1. **Creator verifies the TEST-tab chat fix on the next run**: Test Stream → the drawer should
open with a liveChatId line and Mock Chat Input enabled ~as soon as the broadcast goes live;
send a message and confirm it round-trips through the ~2s poll and renders on the overlay.
2. Push decision is the creator's (repo ~11 ahead). If pushed, note the commit id in this file.
3. When scoped: TASK 3 item 20 (RewardEvents persistence half) draws next.
## Critical working rules (unchanged, still binding)
- **Good Dog = ONE integration test per change.** Scope lock + `./scripts/scope-check.sh` before commit.
- Windows dotnet host for all WSL builds (`/mnt/c/Program Files/dotnet/dotnet.exe`, quoted paths).
- 0 warnings on real clean builds (verify.sh only, never incremental). One runtime model.
- No menus/polls with the creator; decisions asked once then held; do the work, then report.