Files
LlamaCasty/HANDOFF.md
T
gramps d4aa588da0 feat(alerts): TASK 43 — native events & alerts (six unique animations) + chat parity
Replace the external StreamElements feed with NATIVE YouTube events per the creator's
2026-09-23 question.

Chat parity half:
- YouTubeChatService decodes ALL SIX liveChat/messages event types into
  ChatMessage.Kind (superChat/superSticker/newSponsor/membershipGifting/
  giftMembershipReceived/memberMilestoneChat) — the four formerly-empty overlay
  rows are real now — and re-arms its one-shot poll on the server's
  pollingIntervalMillis (streamList connection semantics; clamp 1000-6000ms,
  maxResults=2000). ParsePage internal static seam + ChatPage record for
  deterministic tests; optional HttpClient ctor seam kept; InjectSimulatedMessage
  (TASK 41) preserved.

Alerts half (creator rulings: one celebration zone, six UNIQUE animations, no
menus/polls, sub mention = chat row only, NO viewer count):
- New SourceType.AlertBox 'Stream Alerts' (one per layout, CanAddAlerts gate
  mirroring chat; idle = transparent).
- AlertRenderer: 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), every card
  drawing the 'made with LlamaCasty!' brand line.
- AlertOverlayLayer: true component (Commit-G pattern) — queue (cap 10, drop tail
  never stall), 33ms UI ticker, cache-first RenderFrame + UpdatePreview,
  Advance(double) as the deterministic test clock; ChatEventKind.None rows never
  enqueue.
- Wired: resolver RenderAlertBox, _alertLayer ctor + dispose, LoadLayout previews,
  Add menu item (Controls/LeftPanel.xaml), TestSessionViewModel sims tagged
  (member->NewMember, superchat->SuperChat).

Good Dog ONE integration test: AlertLayerTests (RealApp STA, real WPF raster) —
ParsePage classifies all six kinds + cadence fields; None rows enqueue nothing;
six events play pairwise-distinct moving frames then drain to null.

Gate: clean build 0 warnings; full suite 316/317, the one failure
(LayerReorderPersistenceTests.RealMouseDrag) repros on the clean tree — the
known environmental class (real-mouse-drag no-ops with a game/fullscreen window
focused).

References (OBS/overlay ecosystem):
- streamList semantics: https://developers.google.com/youtube/v3/live/docs/liveChatMessages/streamList
- OBS alert-box pattern (designated celebration zone, idle transparent): creator-chosen model
2026-09-24 08:27:00 -07:00

81 lines
5.4 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-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.