# TASK 25 — Background consolidation: one locked Background per screen + mini-view rule > Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here. ### Status: ✅ Done (shipped 2026-08-23, branch `task25-backgrounds`) The creator rejected the multi-concept background model ("why are there multiple background things?"). Locked model, verbatim intent: 1. **Exactly ONE background per screen**, named "Background", at position 0. 2. It cannot be re-ordered or deleted; **no Background/Screen item in the (+) menu**. 3. Context-sensitivity exists **only on the Live screen** (Show Desktop toggle + monitor switching — behavior kept intact). 4. **Exactly five default background images** live in the DB; stale rows are cleaned up. ### What shipped: - **Seeder consolidation:** the five near-clone seeders (`Seed{Starting,Brb,Ending,Chat}Background`, `SeedLiveBackgroundAsset`, `EnsureDefaultBackground`) are gone. One path now: `EnsureBackground(scene)` → `CreateBackground(name)` — Live = `DisplayCapture` row (capture machinery untouched), everything else = static `Background` art row; both named "Background". - **Heal on every load:** `NormalizeBackgrounds(scenes)` keeps the correctly-flavored row, converts a wrong-flavor survivor in place (`Source.Type`'s setter derives `IsBackground` — conversions must re-assert the flag), drops duplicates, seeds missing ones, renames, pins to index 0; non-canonical scenes lose backgrounds + flag. `HealBackgrounds()` stamps default art (`Assets/{scene}-background.jpg` via `AddAsset`; custom Browse art wins). This fixed the real DB's rot: four scenes carried a stray "Game Capture" duplicate beside their static row, and Settings held 16 orphaned `BackgroundUseDefault_{guid}` keys. - **Settings purge:** `LayoutStore.Save` deletes `BackgroundUseDefault_{id}` / `BackgroundPath_{id}` keys whose id is no longer a Source row. - **(+) menu:** Screen + Background items removed → Webcam/Image/Text/Countdown/Web/YouTube Chat; `AddSource` also hard-refuses DisplayCapture/WindowCapture/Background parameters. - **Capture controls Live-only:** `CanChangeBackground` = staged scene is Live. The preview CanvasGrid menu (Show Desktop/Capture Desktop/Refresh Desktop) binds it directly; the layer-row context menu MultiBindings it with the row's `IsBackground` through a new `Helpers/AllTrueToVisibilityConverter`. Non-Live screens keep the Use-default pill + Browse. - **Mini rule:** minis never render live captures. While Live is staged its mini shows the green placeholder; unstaged it shows `live-background.jpg`. Fixed by making `LoadBackgroundImage` flavor-blind (`IsBackground`) and gating staged-Live to the placeholder in `RefreshSnapshotsAsync`. (Real-time rendering stays center-monitor-only — preview lag during live gameplay is a known unsolved OS-level problem and must not be compounded.) ### Tests (suite went 221/218 → 223/220; the two stale background-policy landmine tests healed here): - Integration (the ONE): `BackgroundHealIntegrationTests` — seeds a dirty temp DB (duplicate rows, misnamed Live row, orphaned keys), drives the real window, asserts one Background per scene at index 0 with correct flavor/name, save purges the orphaned keys. - Unit: SceneCatalogTests rewritten for NormalizeBackgrounds/EnsureBackground flavors; BackgroundTests empty-scene flavor updated; SourceNamingTests excludes the always-present Background from numbered-name expectations.