Files
LlamaCasty/TASKS.md
T
gramps 0981a72eea fix(stream): chat insert 400 — insert body must declare snippet.type
The liveChatId fix (TASK 44) worked on the next Test Stream, but every Mock
Chat Input send returned 'YouTube rejected the message (error 400)'. The
runtime log's body: 400 MISSING_REQUIRED_FIELD, domain
youtube.api.v3.LiveChatMessageInsertResponse.Error.

The liveChat/messages.insert snippet requires type ('textMessageEvent' or
'pollEvent') alongside liveChatId and textMessageDetails.messageText; the
TASK 41 body omitted it, and the Good Dog test asserted only liveChatId +
messageText were present — false-green while real YouTube rejected every
send. Fix body + assert type in the same test so the field can never drop
silently again.

Reference: https://developers.google.com/youtube/v3/live/docs/liveChatMessages/insert

Good Dog: ONE integration test (strengthened TestStream_DockTooling...).
Gate: clean build 0 warnings; full vstest 317/318 (the 1 failure is the
known environmental RealMouseDrag flake — passes 3/3 in isolation).
2026-09-25 08:12:05 -07:00

140 lines
12 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.
# ytLlive — Task List
> **Catalog:** task files live in [`TASKS/`](TASKS/) (one file per task). This file is the
> index. Memory-map conventions: [`schema.md`](schema.md); architecture/decisions: [`ai.md`](ai.md).
> **Checklist markers** — every task's Status line uses the same states:
> 1. ✅ — completed / shipped
> 2. 🔶 — in progress
> 3. ⏳ — blocked / waiting
> 4. ☐ — not started / queued
> 5. ❌ — exception (known-issue, deliberately excluded, or merged)
> **2026-09-01 — v1 = feature-complete ruling:** there is no v1.x. Everything queues to
> v1 or to **"Out of product — permanently"** (file end). Read those two sections before
> adding or reviving anything here.
---
## Task catalog
| # | Task | Status | File |
|---|------|--------|------|
| 01 | Initial Scaffold | ✅ Done | [`TASKS/task-01-initial-scaffold.md`](TASKS/task-01-initial-scaffold.md) |
| 02 | YouTube OAuth2 Authentication | ✅ Done | [`TASKS/task-02-oauth2-auth.md`](TASKS/task-02-oauth2-auth.md) |
| 03 | Capture Pipeline (Scenes/Sources) | 🔶 In progress — 27/30 items done; items 16, 17, 20 open | [`TASKS/task-03-capture-pipeline.md`](TASKS/task-03-capture-pipeline.md) |
| 04 | RTMP Ingest to YouTube | ✅ Done — all 7 items shipped | [`TASKS/task-04-rtmp-ingest.md`](TASKS/task-04-rtmp-ingest.md) |
| 05 | Layout Persistence (SQLite) | ✅ Done | [`TASKS/task-05-layout-persistence.md`](TASKS/task-05-layout-persistence.md) |
| 06 | UI polish batch | ✅ Done | [`TASKS/task-06-ui-polish-batch.md`](TASKS/task-06-ui-polish-batch.md) |
| 07 | Meter scaling amplification | ✅ Done | [`TASKS/task-07-meter-scaling.md`](TASKS/task-07-meter-scaling.md) |
| 08 | Audio milestone | ✅ SHIPPED 2026-08-14 | [`TASKS/task-08-audio-milestone.md`](TASKS/task-08-audio-milestone.md) |
| 09 | YouTube Live Stream Management | ⏳ In progress — items 1–3, 4 shipped; item 5 open; item 6 locked (TASK 36) | [`TASKS/task-09-live-stream-management.md`](TASKS/task-09-live-stream-management.md) |
| 10 | Monetization: watermark-only one-time license + Polar billing | 🔶 In progress — steps 1–7 shipped | [`TASKS/task-10-monetization.md`](TASKS/task-10-monetization.md) |
| 11 | Post-pause polish batch (creator's 8 review issues) | ✅ SHIPPED 2026-08-15 | [`TASKS/task-11-polish-batch.md`](TASKS/task-11-polish-batch.md) |
| 12 | Master limiter on the live mix | ☐ Queued | [`TASKS/task-12-master-limiter.md`](TASKS/task-12-master-limiter.md) |
| 13 | Social media launch kit | 🔶 Scoped — queued after v1 | [`TASKS/task-13-social-launch-kit.md`](TASKS/task-13-social-launch-kit.md) |
| 14 | Creator feedback batch | 🔶 In progress — Branch 2 shipped | [`TASKS/task-14-creator-feedback-batch.md`](TASKS/task-14-creator-feedback-batch.md) |
| 15 | Stock scene background images | ✅ Shipped | [`TASKS/task-15-scene-backgrounds.md`](TASKS/task-15-scene-backgrounds.md) |
| 16 | Kill infinity display | ✅ Shipped | [`TASKS/task-16-kill-infinity-display.md`](TASKS/task-16-kill-infinity-display.md) |
| 17 | Web source rendering (WebView2) | ✅ Done | [`TASKS/task-17-web-source-rendering.md`](TASKS/task-17-web-source-rendering.md) |
| 18 | Local recording | ✅ Shipped `a9eb360` (2026-08-29) | [`TASKS/task-18-local-recording.md`](TASKS/task-18-local-recording.md) |
| 19 | Scene transitions | MERGED → TASK 23 (Control Surface UX) | [`TASKS/task-19-scene-transitions.md`](TASKS/task-19-scene-transitions.md) |
| 20 | Hotkeys (keyboard shortcuts) | ✅ Done — shipped 2026-08-26 | [`TASKS/task-20-hotkeys.md`](TASKS/task-20-hotkeys.md) |
| 21 | Media source (video file playback) | 🔶 In progress — UI picker remaining | [`TASKS/task-21-media-source.md`](TASKS/task-21-media-source.md) |
| 22 | Audio sync offset | ✅ Done (2026-08-31) | [`TASKS/task-22-audio-sync-offset.md`](TASKS/task-22-audio-sync-offset.md) |
| 23 | Studio mode | MERGED → TASK 23 (Control Surface UX) | [`TASKS/task-23-studio-mode.md`](TASKS/task-23-studio-mode.md) |
| 24 | Toast notifications | ✅ Done (2026-08-23) | [`TASKS/task-24-toast-notifications.md`](TASKS/task-24-toast-notifications.md) |
| 25 | Background consolidation | ✅ Done (2026-08-23) | [`TASKS/task-25-background-consolidation.md`](TASKS/task-25-background-consolidation.md) |
| 30 | Gear menu cleanup + Default Location for Recordings + preview layout | ✅ Done (2026-08-29) | [`TASKS/task-30-gear-cleanup-preview-layout.md`](TASKS/task-30-gear-cleanup-preview-layout.md) |
| 31 | SceneGraph component + static/dynamic compositor optimization | ✅ Done (2026-08-31) | [`TASKS/task-31-scenegraph-optimization.md`](TASKS/task-31-scenegraph-optimization.md) |
| 32 | Stream resilience | ☐ Queued (2026-09-01) | [`TASKS/task-32-stream-resilience.md`](TASKS/task-32-stream-resilience.md) |
| 33 | Bandwidth auto step-down | ☐ Queued (2026-09-01) | [`TASKS/task-33-bandwidth-step-down.md`](TASKS/task-33-bandwidth-step-down.md) |
| 34 | Scheduled streams (Text-drawer version) | ☐ Queued (2026-09-01) | [`TASKS/task-34-scheduled-streams.md`](TASKS/task-34-scheduled-streams.md) |
| 35 | Scene-linked audio | ☐ Queued (2026-09-01) | [`TASKS/task-35-scene-linked-audio.md`](TASKS/task-35-scene-linked-audio.md) |
| 36 | Gold pass | ☐ Queued (2026-09-01) | [`TASKS/task-36-gold-pass.md`](TASKS/task-36-gold-pass.md) |
| 37 | Defaults vs current layout split | ☐ Queued (2026-09-20) | [`TASKS/task-37-defaults-current-split.md`](TASKS/task-37-defaults-current-split.md) |
| 38 | Capture Window… backdrop (in-app window picker) | ✅ Done — shipped 2026-09-21 | [`TASKS/task-38-window-backdrop.md`](TASKS/task-38-window-backdrop.md) |
| 39 | YPP journey tracker (slice 1: current-scope data) | 🔶 Slice 1 ✅ — 2026-09-22; **refresh 403 fixed 2026-09-23** (auditDetails part dropped); slice 2 (Analytics + ETA) queued | [`TASKS/task-39-ypp-journey-tracker.md`](TASKS/task-39-ypp-journey-tracker.md) |
| 40 | App Settings round: active-camera picker + config dialog, gear move, defaults, accent | ☐ Queued (2026-09-22) — plan saved | [`TASKS/task-40-app-settings-round.md`](TASKS/task-40-app-settings-round.md) |
| 41 | Test Stream mode: private test broadcast + TEST drawer (mock chat input + simulated events) | ✅ Done (2026-09-22) | [`TASKS/task-41-test-stream-mode.md`](TASKS/task-41-test-stream-mode.md) |
| 42 | Top bar redesign: one REC-or-Stream surface, gear up top, sign-in/account zone world-gated | ✅ Done (2026-09-22) | [`TASKS/task-42-top-bar-redesign.md`](TASKS/task-42-top-bar-redesign.md) |
| 43 | Native events & alerts: chat parity (all six event types + server poll cadence) + six-animation native alert box | ✅ Done (2026-09-24) | [`TASKS/task-43-native-alerts.md`](TASKS/task-43-native-alerts.md) |
| 44 | TEST-tab chat fix: resolve liveChatId from snippet (not contentDetails) + poll until the broadcast is live | ✅ Done (2026-09-25); full suite 318/318 | [`TASKS/task-44-test-chat-fix.md`](TASKS/task-44-test-chat-fix.md) |
| 45 | TEST-tab chat fix #2: insert body must declare `snippet.type` (400 MISSING_REQUIRED_FIELD) | ✅ Done (2026-09-25) | [`TASKS/task-45-chat-insert-type.md`](TASKS/task-45-chat-insert-type.md) |
---
## Open items (at a glance)
- **TASK 3** — items 16 (Text source) + 20 (RewardEvent capture → SQLite, Alerts' persistence half) open; **17 (Alerts) is DONE via TASK 43 (2026-09-24) — native six-event alert box**
- **TASK 9** — item 5 open (webcam identity key reconciliation)
- **TASK 10** — Velopack update URL pending
- **TASK 12** — queued future
- **TASK 13** — queued post-v1
- **TASK 14** — Branch 2 shipped; branch 3+ in progress
- **TASK 21** — UI picker slice remaining (Windows-only verification pending)
- **TASK 32–36** — all queued future work (2026-09-01)
- **Webcam resource lifecycle (2026-09-17)** — startup slice shipped (OS poll at start, single-camera
auto-lock, persistent red alert in the Layers panel on lock failure, re-polls until resolved); gate
slice shipped same day — webcam = app-level default, one per stream per scene, Add places the
default directly, offered only when a camera is ATTAINABLE (identity + live session, not just a
saved identity), app base lock keeps the session after the last placement is removed, startup
adopts a solo camera as default. TASK 26's app-wide gate superseded by creator directive. The App
Settings webcam selector is now **TASK 40 Unit A** (plan saved 2026-09-22). Remaining next slice
(user-queued): static (+) catalog rows (Background, YouTubeEvent, quoted labels) with reason-greying.
- **TASK 40 — App Settings round** — plan saved 2026-09-22 (`TASKS/task-40-app-settings-round.md`),
four units, one Good Dog test each: **A** active web camera section under Recordings (Change…
sub-menu = live enumeration incl. vcams; Tune… config dialog via `ICameraControlProbe`, live-only
tweaks), **B** gear moved top-left right of the wordmark (left-click App Settings, right-click
Bug/Feature/About), **C** persist output resolution default + surface default scene
transition/duration + confirm-before-End, **D** accent/theme color (consolidate 69 hardcoded
accent sites into a DynamicResource brush + picker). **Unit B (gear) is DONE early** — shipped 2026-09-22
as part of TASK 42 (top bar redesign): gear top-right of the brand, single click = the Settings/Bug/
Feature/About menu, removed from BottomBar. A + C + D remain queued.
- **TASK 37** — queued (2026-09-20): split the layout data into a `default` set (the established DB)
and a `current` set carrying the build-id; a saved `current` is honored only by the same build-id,
otherwise defaults load — enables one-click revert to defaults too. Capture needed work OUT of
current scope here; do not bolt it onto an in-flight change.
- **TASK 41 — Test Stream mode** — DONE 2026-09-22 (`TASKS/task-41-test-stream-mode.md`): a Test
button next to Start runs the real private-only go-live pipeline with `IsTestStream` set, and the
TEST drawer (right rail, third tab) hosts Mock Chat Input (real `liveChat/messages.insert` → ~2s
poll round-trip renders on the overlay) + simulated Subscriber/New Member/Super Chat events that
inject through the poller's `MessageReceived` seam (`IsSimulated` — YouTube's insert API only
creates text, so these are local-only by design; styled member/SuperChat rows validate the chat
overlay). **Real Stinger/TTS alert widgets resolved by TASK 43's native alert box.**
- **TASK 43 — Native events & alerts** — **DONE 2026-09-24** (`TASKS/task-43-native-alerts.md`):
StreamElements replaced with NATIVE YouTube events. Chat parity half: `YouTubeChatService` now
decodes all SIX `liveChat/messages` event types (`ChatEventKind` on `ChatMessage`) — the four
formerly-empty event rows fixed — and re-arms its poll on the server's `pollingIntervalMillis`
(streamList semantics, clamp 1000–6000ms, `maxResults=2000`). Alerts half: a new
**`SourceType.AlertBox`** ("Stream Alerts", one per layout) is an OBS-style celebration zone
where the six events play **six unique branded animations** (`AlertRenderer` + the
`AlertOverlayLayer` component; 33ms ticker, deterministic `Advance` test clock; idle =
transparent). Creator rulings baked in: free-sub mention = chat row only (no sub alert — YouTube
emits none), NO viewer count, every alert card carries the "made with LlamaCasty!" brand line.
- **TASK 44 — TEST-tab chat fix** — **DONE 2026-09-25** (`TASKS/task-44-test-chat-fix.md`):
the open creator report ("I still cannot post a chat message in the TEST tab") was a single
cause: `GetBroadcastLiveChatIdAsync` read `contentDetails.liveChatId` (lifeChatId lives in
**`snippet`**) AND ran before the broadcast was live (RTMP push flips ready→live via
enableAutoStart; YouTube only populates the id on live broadcasts — official GetLiveChatId.java
sample lists broadcastStatus=active). Fixed by reading `snippet.liveChatId` and polling with a
bounded retry after the frame pump starts; chat stays non-fatal.
---
## YouTube Live API research facts
See [`TASKS/research-youtube-api.md`](TASKS/research-youtube-api.md) — authoritative facts for v3 build.
---
## Out of product — permanently
These were explicitly ruled out:
- **D3D11 swap compositor** (superseded by software compositor; TASK 3 item 16)
- **Background removal** (ONNX/DirectML; TASK 3 item 19)
- **OBS-style source expansion** (game capture, browser source, media playlist, VLC, color-key, MIDI — the minimal source set is deliberate; creators who need more have graduated to OBS)
- **Multi-layout** (auto-save, single layout; multi-layout = OBS territory)
- **Cross-process stream resume** (API makes it impossible; creator ruling 2026-09-01)