# HANDOFF — 2026-09-24 (TASK 43 shipped: native events & alerts — creator said "go") ## Branch / Commit State `main` HEAD = new commit for TASK 43 (native events & six-animation alert box); previous: `3a4e17c` (account zone world-independent), `cb75066` (YPP 403), `d72949e` (top-bar feedback), `ac6e67a` (end close-out). Repo is ~10 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 (this turn, creator said "go") The creator asked (2026-09-23) whether the app could use **native YouTube events instead of StreamElements**. Research pinned the API facts; creator rulings locked the product shape. One combined work unit ("go"), task filed as **TASK 43** (`TASKS/task-43-native-alerts.md`): 1. **Chat parity half** — `YouTubeChatService` now decodes **all six** `liveChat/messages` event types into `ChatMessage.Kind` (the four previously-empty event rows are real now) and re-arms its poll on the server's `pollingIntervalMillis` (streamList semantics; clamp 1000–6000ms, `maxResults=2000`). 2. **Alerts half** — new **`SourceType.AlertBox`** ("Stream Alerts", one per layout, `CanAddAlerts` gate mirroring chat): an OBS-style celebration zone, idle = transparent. `Services/AlertRenderer.cs` draws **six DISTINCT branded animations** (SuperChat slide-up/ shine/count-up; SuperSticker scale-pop; NewMember drop-in/flash; MemberGift slide-left/chip-fan; GiftReceived confetti; MemberMilestone rise/growth-bar), each card carrying the "made with LlamaCasty!" brand line (free product placement per broadcast). `Services/AlertOverlayLayer.cs` is a true component (Commit-G pattern): queue (cap 10) + 33ms ticker + cache-first `RenderFrame` + `UpdatePreview`; **`Advance(double)` = deterministic test clock**. 3. **Creator rulings baked in:** no menus/polls (asked once, held); free-sub mention = chat row only, **no sub alert** (YouTube emits none); **no viewer count** (vetoed — demotivating, weaponizable); six events = six unique animations, not a recolored template. **Good Dog:** `ytLive.Tests/AlertLayerTests.cs` (RealApp STA, real WPF raster) — ParsePage classifies all six kinds + cadence fields; playback never enqueues a `None` (sub-mention) row, plays six pairwise-distinct moving frames, drains to idle. **Gate: clean build 0 warnings, 316/317** — the ONE failure (`LayerReorderPersistenceTests.RealMouseDrag…`) repros on the CLEAN tree (proved via `git stash` + rebuild + isolated run): a real-mouse-drag test that no-ops while a game/fullscreen window steals the mouse (the HANDOFF-documented environmental class). **NOT a regression — do not chase it in-app; close games and rerun if in doubt.** ## Follow-ups queued (NOT done in this unit) - **Creator report still open — not yet diagnosed:** "I still cannot post a chat message in the TEST tab." The TEST drawer's Mock Chat Input posts a REAL `liveChat/messages.insert`; the fix needs its own scoped unit. - **TASK 3 item 20 persistence half** — the canonical `RewardEvents` SQLite table + `superChatEvents.list` (30-day) backfill + session-report rollup (the shipped alert path parses events to `ChatMessage` in memory; the report reads that table once it exists). - 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`. - New facts recorded: the chat feed IS the event feed (six types, no sub event); streamList is a connection-semantics description of that same endpoint (pollingIntervalMillis drives cadence). - 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 alerts unit on the next run**: Add → Stream Alerts, then (Test Stream drawer) Simulated Super Chat / New Member — confirm the zone stays transparent at idle and each event plays its own animation on the canvas and preview; a real Super Chat during the next live run confirms the real path. 2. Push decision is the creator's (repo ~10 ahead). If pushed, note the commit id in this file. 3. When scoped: diagnose the TEST-tab chat posting report ("I still cannot post a chat message in the TEST tab") as its own Good-Dog unit. ## 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.