# HANDOFF — 2026-09-26, end of session (take four: ticker display methods) ## Where we are `main`, **5 local commits ahead of `origin/main` (= `ecb329e`), NOTHING PUSHED.** Last pushed commit is still `ecb329e`. Do not push without the creator saying so. | commit | what | |---|---| | `a11b15e` | TASK 47 alert video (first landing) | | `7b940b6` | poller-thread marshal crash fix | | `80038ff` | silent-decoder fallback + diagnostics | | `aea0670` | video pacing via `FfmpegFrameRateProbe` | | `e2ecc24` | **the real alert fix: `PreviewPane.xaml` `IsAlertBox` trigger** + 2 Good Dog tests + resolver/preview diagnostics | | (last, unpushed) | **alert announcement strip: visible in the preview + 3 display methods** (Scroll / Flash / Solid), paced in reads-per-alert | ## THE ANSWER, take two (do not re-derive this) The **ticker was output-only**. `AlertTickerFrame` existed solely as a frame-pump callback (blitted at 0,0 into the OUTPUT). `PreviewPane.xaml` had no element for it because the strip is master-width and GLOBAL, not a `Source`, so it cannot ride a per-element `Image`. Nothing was broken in the renderer — there was simply no consumer in the preview. Fixed with a `tickerPreviewSink` on `AlertOverlayLayer` (published from `RefreshAlertPreviews()`, UI thread only) + `MainViewModel.AlertTickerImageSource` + a global `AlertTickerElement` in `PreviewPane.xaml` mirroring `SocialBarElement`. The marquee was also **unreadably paced**: a fixed `140px/s` needed ~17s per pass, so a 10s alert showed the message barely once, entering from the right and never crossing. It is now paced in **reads per alert** (`TickerReadsPerAlert = 3` inside the alert's own length), which is the incumbent's own unit (Streamlabs: "Alert Duration" + "Text Delay", never a scroll-speed slider). ## THE ANSWER (do not re-derive this) The alert video was **never drawn**, never mis-decoded. Build 90's diagnostics showed `Alert preview: frame=680x200 a255` and `Output resolver: frame 680x200 playing=True` every second for the whole clip — a real, opaque, correctly-sized frame reaching BOTH consumers. `Controls/PreviewPane.xaml` keeps the per-element `Image` `Collapsed` unless a DataTrigger fires, and there was **no `IsAlertBox` trigger** (only IsImageSource / IsChatBox / IsWebSource / IsWebcam). Chat boxes rendered; alert boxes never could. Removing/re-adding the layer could not have fixed it. Clip itself is fine: DB asset `941785b0-d022-45fa-a8a2-2cd59ae2ba48` is byte-identical (md5 `0ee1f4960dd3b23dee5930a2af79d410`) to the creator's `C:\Users\gramp\Downloads\llamacasty-dancingLlama-thankyou.mp4` — h264 1280x720 10s, every sampled frame full bright content. ## Working tree Clean apart from the uncommitted work unit above (it is committed; check `git status`). If the app is running, `ytLive.dll`/`.exe` are LOCKED and any build fails with MSB3021/ MSB3027 — the creator must close ytLive first. That is normal, not a broken build. ## Build / test commands (Windows host, always) ```bash "/mnt/c/Program Files/dotnet/dotnet.exe" build "C:\Users\gramp\Documents\Code\projects\ytLive\ytLive.csproj" --no-restore "/mnt/c/Program Files/dotnet/dotnet.exe" vstest "C:\Users\gramp\Documents\Code\projects\ytLive\ytLive.Tests\bin\Debug\net8.0-windows10.0.19041.0\ytLive.Tests.dll" ``` Last full suite: **339/339 pass** (15 new facts for the ticker feature). Run it with ytLive CLOSED or the RealMouseDrag env flake fires. ## Queued next (creator's words, 2026-09-26) — the Good Dog queue 1. **Test-console chat must not clear the chat window.** "when I add a chat message from the test console, or from any console, that chat text should not clear the current chat window." 2. **Test pull-out chat input: 20px right padding** — the text box is clipped at the right edge of the div; needs 20px padding against the div's right side. 3. **Test pull-out chat input: Enter inserts a newline**, it must not send. 4. ~~Verify the alert video live~~ — **DONE, the creator confirmed it plays.** 5. **Verify the three ticker display methods live** (Scroll / Flash / Solid) and pick a default. Flash is 0.5s on / 0.5s off; Solid is centred; Scroll does 3 passes per 10s alert. Nothing here has been SEEN on screen yet — the tests prove pixels and bindings, not the look. 6. **Decide whether the once-per-second alert diagnostics stay.** `ViewModels/MainViewModel.cs` (`ResolveOutputFrame`) and `Services/AlertOverlayLayer.cs` (`UpdatePreview`) still log `Alert preview:` / `Output resolver:` once a second while an alert plays. They earned their keep; they are noise in normal use. Creator's call. ## Landmines / facts worth keeping - The pinned BtbN ffmpeg has **no libx264** — generate test clips with `-c:v mpeg4`. - **A bound `ItemsSource` ComboBox in `LeftPanel.xaml` breaks `LayerReorderPersistenceTests.RealMouseDrag_OnTheLayerList_PersistsTheReorder`** (it injects PHYSICAL mouse input, so a load-time re-measure moves the rows out from under the cursor). Use inline ``s like the chat Font selector does. If a UI-only change breaks a real-input test, suspect the control's binding STYLE first, and bisect with `git checkout `. - The `Source` row is read back by **POSITIONAL** index in `LayoutStore.Load.cs` (`GetInt32(32..34)`). Append new Source columns to the END of the SELECT, or a mid-list insert silently shifts a neighbour instead of failing to load. New columns use the idempotent `PRAGMA table_info` guard in `LayoutStore.Migrations.cs` (no `user_version` bump needed). - **A seamless marquee never goes blank** (the wrapped copy enters from the right as the pill clears the left), so an "empty frame" cannot count a pass — count the pill's leading edge resetting to the right edge. - `SceneCompositor.Render` fills its base with **opaque black**, so "any non-zero byte" is not proof a layer painted. Compare against an idle render, or count COLOURFUL px. - `sqlite3` on WSL: `/home/gramps/android-sdk/platform-tools/sqlite3`. Extract a BLOB with `SELECT writefile('/tmp/opencode/x.bin', Data) FROM Asset WHERE Id='…'` (Linux paths only — a `C:/…` path creates a junk `C:` dir IN THE REPO; one was made and removed). - Layout DB: `/mnt/c/Users/gramp/AppData/Roaming/ytLlive/ytLlive.db` (tables: `Asset` `Id/Hash/Data`, `Settings`, `Source`, `Scene`, …). Alert default video setting key: `AlertDefaultVideoAssetId`. ffmpeg/ffprobe live in `/mnt/c/Users/gramp/AppData/Roaming/ytLlive/tools/` (run the `.exe` directly from WSL). - Two diagnostics were ADDED and are still in the tree (once-per-second, alert only): `Output resolver: alert box …` (MainViewModel.cs) and `Alert preview: box …` (AlertOverlayLayer.cs). Decide with the creator whether to keep them or strip them now that the root cause is known. - `PreviewPane.xaml` has the same latent gap for `IsMediaSource` (no trigger either) — NOT fixed (out of scope), noted as a follow-up. - Known perf item, untouched: FramePump stalls ~140-180ms renders (`render=full-render split=0 … totalMs=140`). Unrelated to the alert bug. - YouTube rejects the `complete` transition (403) at end-of-stream; `enableAutoStop` finishes the broadcast. Harmless, already handled.