Backgrounds: one locked Background per screen + mini rule (TASK 25)

This commit is contained in:
2026-08-23 13:33:33 -07:00
parent b400ab59c5
commit 7dd140a4c0
13 changed files with 554 additions and 309 deletions
+38 -14
View File
@@ -1,30 +1,54 @@
# HANDOFF — Session State
## Branch
`task24-notifications` (from `main` @ `809c066`, which is pushed) — **dirty, uncommitted**, TASK 24 complete and green.
`task25-backgrounds` (from `task24-notifications` @ `b400ab5`, committed) — **dirty, uncommitted**, TASK 25 complete and green.
## Uncommitted work: TASK 24 toast notifications — COMPLETE, ready to commit
## Uncommitted work: TASK 25 background consolidation — COMPLETE, ready to commit
1. **Library:** `Notification.Wpf` 11.0.0 added to `ytLive.csproj` (MIT; notice #10 in `THIRD-PARTY-NOTICES.txt`). Restore pulls `Notification.CoreUI` 11.0.0 + `Microsoft.Xaml.Behaviors.Wpf` 1.1.142 + DI.Abstractions 10.0.8.
2. **Seam:** `Services/INotificationService.cs` (`Show(title, message, AppNotificationSeverity)` + Info/Success/Warning/Error extensions); `Services/NotificationService.cs` impl — pure `BuildRequest` mapping + `Cards` tint table, Dispatcher-marshalled Show. Host: `NotificationArea x:Name="ToastArea"` last child of MainWindow root grid (`RowSpan=4`, bottom-right above footer, `Margin="0,0,12,96"`).
3. **Call sites** (`ViewModels/MainViewModel.cs`): 5 MessageBox migrations (webcam ×2 → Warning, image read → Warning, sign-in unsuccessful → Warning / failed → Error) + 7 log-only promotions (go-live prep ×3 Error, frame-pump death Error, mic-missing Warning, premium-lapse Warning, saved-session sign-out Info). Offline license re-validation skip left log-only on purpose; SocialsDialog slot-delete confirm stays modal. `_notifications` field initialized at declaration (VM built from XAML).
4. **Tests:** unit `NotificationServiceTests` (8 cases: routing/lifetimes/tints) + the ONE integration `NotificationAreaIntegrationTests.Info_Auto_Dismisses_And_Error_Sticks` (real window-hosted area; visual-tree reads marshalled via `_app.Run`).
5. Build **0 warnings**; **221 total, 218 pass** — only the 3 pre-existing failures below.
Locked model (user directive): exactly ONE "Background" per screen at index 0, non-deletable/
non-reorderable, NOT in the (+) menu; capture context-sensitivity only on the Live screen
(Show Desktop/monitor switching kept intact); exactly five default images in the DB; stale rows cleaned.
1. **Seeders consolidated** (`ViewModels/MainViewModel.cs`): five clone seeders + `EnforceBackgroundPolicy`
deleted. Now: `EnsureBackground` → `CreateBackground(name)` — Live = DisplayCapture row, others =
static Background art row, all named "Background". `NormalizeBackgrounds(scenes)` heals any layout:
correct-flavor keep (in-place Type conversion re-asserts `IsBackground` because `Source.Type`'s setter
derives it), duplicates dropped, missing seeded + INSERTED, index 0, non-canonical stripped.
`HealBackgrounds()` = Normalize + `StampDefaultBackgroundAsset` (pack-resource art via `AddAsset`;
custom Browse wins). Called from LoadLayout, StagedScene setter, ReacquireScreenCaptures.
2. **Settings purge:** `LayoutStore.Save` deletes orphaned `BackgroundUseDefault_{id}`/`BackgroundPath_{id}`
keys (ids gone from Source). Fixes the real DB's 16 stale keys.
3. **UI:** (+) menu Screen+Background items removed (`MainWindow.xaml`); `AddSource` refuses capture/background
params. `CanChangeBackground` = staged-is-Live → gates preview CanvasGrid menu directly and the layer-row
menu via new MultiBinding converter `Helpers/AllTrueToVisibilityConverter.cs` (row Tag carries VM bool).
4. **Mini rule:** minis never render captures. `LoadBackgroundImage` is flavor-blind (`IsBackground`) — fixes
green mini bug (was `Type==Background`, missed Live's DisplayCapture row → placeholder twin at old :951 too);
`RefreshSnapshotsAsync` shows green placeholder only while Live is staged, otherwise its stored art.
5. **Tests:** suite 221/218 → **223 total, 220 pass**. The ONE integration test:
`BackgroundHealIntegrationTests.Dirty_Layout_Heals_To_One_Locked_Background_Per_Scene` (seeds dirty temp DB,
real window, asserts heal + save purges keys). Unit: SceneCatalogTests rewritten (NormalizeBackgrounds heal +
strip + per-scene flavor), BackgroundTests empty-scene flavor updated, SourceNamingTests filters IsBackground.
The two stale landmine tests (#2/#3) are healed by this branch — see below.
6. **Docs same commit:** ai.md (TASK 25 model section replaces backdrop-era text), TASKS.md TASK 25 entry,
Services/index.md (LayoutStore purge), Helpers/index.md (new converter), this file.
7. Build **0 warnings**.
## ⚠️ Landmines
- **User verdict (2026-08-23):** "The AI wrote fucked up code after repeatedly and intentionally misunderstanding instructions." Extends the ai.md 2026-08-22 audit flag — trust nothing from those sessions without manual verification.
- **Pre-existing test failures are THREE (not caused by this branch):**
- **Pre-existing test failure is now ONE (not caused by these branches):**
1. `AudioPipelineTests.Mix_HonorsProviderGains_AndGameMute_KillsTheLoopback`
2. `SourceNamingTests.Duplicate_Sources_Get_Next_Free_Numbered_Name` (StagedScene seeds a "Game Capture" the test doesn't filter)
3. `SceneCatalogTests.EnforceBackgroundPolicy_Sets_Flag_For_All_Scenes` (asserts against elements never inserted)
- Former #2 SourceNaming / #3 SceneCatalog policy tests were repaired BY TASK 25 (expectation updates to the locked model) — not skipped, not deleted.
- **Real-MainWindow tests MUST set `LayoutPathOverride`** (ai.md) — DB pollution wiped real data once.
- Notification.Wpf gotchas (recorded in ai.md/TASKS.md): area routing by XAML `Name`; unknown AreaName silently drops; `NeverExpires()` = `TimeSpan.MaxValue`; `ToHex()` = `#AARRGGBB`.
- **`Source.Type` setter derives `IsBackground`** (Models/Source.cs:40) — any Type change must re-set IsBackground after.
- **vstest quirk:** only one `--tests:` param allowed; plain substrings work (`--tests:BackgroundHeal`), alternation regexes silently match nothing.
- Notification.Wpf gotchas (ai.md/TASKS.md): area routing by XAML `Name`; unknown AreaName silently drops; `NeverExpires()` = `TimeSpan.MaxValue`; `ToHex()` = `#AARRGGBB`.
## Next steps
1. Commit this branch (code + docs + notices, one commit), then merge/PR per Good Dog Rule (one integration test ✓).
2. User visual pass on Windows: toasts look right bottom-right, error sticky with close button, no overlap with footer/chat.
3. Then the stale background tests repair queue (unit-level): SourceNaming filter + SceneCatalog policy test.
1. Commit this branch (code + docs, one commit), then merge/PR per Good Dog Rule (one integration test ✓).
2. User visual pass on Windows: minis show art when unstaged (Live included), green placeholder while staged;
no Game Capture rows in layer lists; (+) menu trimmed; capture controls only on staged Live.
3. Then relaunch app once so the user's real `%APPDATA%` DB self-heals on load + first save purges stale keys.
## Build
```bash