Files
LlamaCasty/HANDOFF.md
T
gramps 5a1993b6db fix(persist): one shared z-order across Source + WebcamSceneConfig rows
A webcam dragged between sources reverted to the bottom of the stack on
every relaunch: Source and WebcamSceneConfig each carried independent
per-type SortOrder counters, and Load appended all Sources before all
configs. Save now stamps both tables' SortOrder from the element's index
within scene.Elements; Load merges the two tables' rows by that shared z
(sources-first tie-break preserves legacy rows). Cross-type reorder now
survives a fresh LayoutStore reload.

Task 37 queued: defaults vs current layout split (creator directive) —
capture out-of-scope work in TASKS.md rather than folding it in.
2026-09-20 09:23:46 -07:00

133 lines
9.5 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-20 (cross-table z-order bug fixed: webcam between sources survives reload; defaults/current split queued as TASK 37)
## Branch / Commit State
`main` HEAD = **the cross-type ordering fix** (local — no push). This is a CONTINUATION of the
2026-09-18 drag-reorder work: the creator kept insisting the reorder "doesn't save" even after
commit `f91bf87`. Their repro was real and the per-table `SortOrder` theory was the actual mechanism.
**No push yet.** Working tree clean after the ordering-fix commit.
## ✅ Committed — cross-type z-order: webcam between sources survives save→reload (2026-09-20)
**The actual bug the creator reproduced** (`f91bf87` shipped the immediate-save at drop, but the
reorder still reverted on restart): `Source` and `WebcamSceneConfig` are separate tables with
**independent per-type `SortOrder` counters**. Save stamped sources 0..n and configs 0..m;
`LayoutStore.Load` appended **all Sources first, then all WebcamSceneConfigs**. A webcam dragged
between two sources was structurally unrecoverable — the live scene (Background, YouTube Chat,
Image, Web Resource-0 sources + one HD Pro Webcam C920 config) reverted the Webcam to the bottom
of the stack on every relaunch.
**Fix:** one shared z-space per scene. `Save` stamps both tables' `SortOrder` from the element's
index within `scene.Elements` (the non-source branches bump the counter too); `Load` merges the two
tables' rows **by that shared z** instead of appending tables. Legacy pre-unification rows can tie at
0 — ties break sources-first, so old data reads back exactly as it saved.
**Good Dog test** `CrossTypeReorder_BelowTheWebcam_SurvivesFreshReload` (`LayerReorderPersistenceTests`):
seeds the builder's real Live layout (4 sources + `HD Pro Webcam C920` config row), reorders
"Web Resource-0" DOWN below the webcam, calls `OnSceneElementsReordered`, then opens a **brand-new
`LayoutStore` on the same temp DB — the restart** — and asserts the cross-type order holds. **309/309
tests pass, build 0 warnings.**
**Also committed:** TASK 37 queued — **defaults vs current layout split** (creator directive
2026-09-20): the DB should hold the static brandable `default` layout; the `current` layout carries
the build-id (loaded only when it matches `BuildStamp.Id`), enabling one-click revert. Conceptual
shape `scene[0-4].layerList.[default|current].elementList`; config-file vs second-rows-in-DB not yet
decided (`TASKS/task-37-defaults-current-split.md` has both + facts). **Process rule established:**
capture out-of-scope needed work in TASKS.md rather than bolting it onto the in-flight change.
## ✅ Committed earlier — layer-list drag-to-reorder persists (2026-09-18, `f91bf87` + below)
`StagedScene.Elements` reorder (RemoveAt/Insert) bypasses SceneGraph's mutation surface, so the drop
must be trapped + persisted. Fix (2026-09-18): the drag sets `_dragReordered` and `EndListDrag`
funnels the drop through `MainViewModel.OnSceneElementsReordered()` (Sources.cs) =
`SceneGraph.InvalidateBake(staged) + SaveLayoutNow()` — an IMMEDIATE save at drop (no debounce
window). The single write stores BOTH the layer list (SortOrder) AND the preview layout (X/Y/W/H in
the same rows). Tests `LayerReorderPersistenceTests` (real App + temp DB): (1) exact code-behind
mutation + geometry assert; (2) **real-gesture** test `RealMouseDrag_OnTheLayerList_PersistsTheReorder`
(`SetCursorPos` + `mouse_event` on a shown Topmost window) — needs an interactive desktop session
(covered/locked session = pointer no-op = flake). Both green in the 309. **This fix was correct but
INSUFFICIENT — the cross-table bug above is what the builder actually hit.**
## ✅ Committed earlier — webcam app-default gate + attainability (`9d00955`, `75723ac`)
Webcam is an **app-level resource** — ONE app-wide default, usable in every scene that can host it,
NOT blocked by other scenes' placements (creator ruling; supersedes TASK 26). Per-scene gate
`CanAddWebcam` = scene has no config && attainable (`CameraManager.IsRunning(_webcam.DeviceId)` —
a live lock, not a saved identity). Add places the default directly (no picker). Identity survives
last-placement removal; startup lays an app-wide BASE lock (refcount keeps the session alive);
adopts a solo camera as default. Dynamic why-gray tooltip. Tests: `WebcamMenuGateTests`,
`WebcamStartupResourceTests`. The DB truth lives at `%APPDATA%\ytLlive\ytLlive.db` (NOT `layout.db`).
## ✅ Committed earlier — Rename Recording dialog taller + full-screen hook unhooked (2026-09-18)
`RenameRecordingDialog.xaml` Height 230 → 276 → **304** (the +20% revealed the Cancel/Save row also
obscured); Save button named `SaveRecordingButton`. Test `RenameRecordingDialogSizingTests` asserts
textbox bottom + Save button bottom inside the client area. **Teardown leak fix:** `Shutdown()` now
calls `_fullScreenDetector.StopWatching()` — the global `EVENT_SYSTEM_FOREGROUND` hook was never
unhooked, invoking a GC'd `WinEventProc` on the next foreground event → test-host abort.
## ⚠️ Open items
- **Build-id on command-line exit (creator demand, 2026-09-20):** when the app exits under
`dotnet run`, output the build number (`BuildStamp.Id` — a fresh per-build GUID, logged in
`App.xaml.cs:32` as `Build {Id} (compiled {BuiltLocal})`) as return data on the command line.
NOT yet implemented — queued, do not fold into another slice.
- **TASK 37** — defaults/current layout split (see above + `TASKS/task-37-defaults-current-split.md`).
- **Webcam take fix 2 of 2:** native WMF death when `MediaCapture.Failed` fires mid-stream and
`SafeStopAsync` disposes reader+capture while the frame thread sits in `TryAcquireLatestFrame`. No
repro/test — deferred per spin-guard.
- **Multi-camera selector slice (user-queued):** ≥2 webcams → web-cam selection in the App Settings
dialog (gear). Currently ≥2 cameras → nothing shows in settings.
- **Static (+) catalog slice (user-queued):** all catalog rows always listed, greyed with named
reason tooltips.
- **Device re-verify (one take session):** slice-18 cache verdicts; webcam fresh-launch with the
browser holding the camera → red alert that clears after Retry once the browser closes; Live must
OFFER Web Cam while Chat holds it.
- **No push yet** — after the take verdict, decide push with the user.
## Open threads (carried)
- Audio-silence verification — fixed (`724af14`); creator heard real audio.
- Webcam MJPG missing / ~10–14Hz, truncation-with-dynamic-scenes — queued.
- Sync control user-doc tutorial — REQUIRED before 1.0 (creator directive; TASK 22).
- Signed A/V sync: verify the negative (advance) direction on device.
- The 2026-09-18 "reorder doesn't save" stale-binary theory — RETRACTED 2026-09-20. The builder was
right; the cross-table z-order bug above is the real mechanism. Never re-air the stale-binary claim.
## Landmines
- testhost shares startup.log — filter by time; the app also writes fake-device failures
('test-camera', 'dev-physical-9') from CameraManager unit tests.
- `cmd.exe /c "taskkill /F /IM ytLive.exe"` (WSL double-slashes mangle) before rebuilds — a live
app process locks `ytLive.exe` (MSB3021).
- Build/tests: **Windows dotnet host** (`/mnt/c/Program Files/dotnet/dotnet.exe`). 0 warnings —
only `./scripts/verify.sh "<files>"`'s clean build counts. Running `ytLive.csproj` alone does NOT
rebuild `ytLive.Tests.dll` — run the Tests csproj before `vstest`. Known audio flake:
`Mix_HonorsProviderGains_AndGameMute_KillsTheLoopback` — stale loopback sample in the pipe when the
mute flips. Unrelated; do not "fix" inside another slice.
- **Assert footguns in this repo's xUnit:** `Assert.Null(x, "msg")`/`Assert.Single(coll, "msg")` do
NOT take a message — the 2-arg overloads mean something else (predicate/item). Empty message = 1 arg.
- The webcam's real state lives in `%APPDATA%\ytLlive\ytLlive.db` (`layout.db` there is a 0-byte
legacy file). sqlite3 at `/home/gramps/android-sdk/platform-tools/sqlite3`.
- FramePump tests asserting per-frame CONTENT need a STABLE scene; cache-sensitive assertions can't
use a call-count resolver flip (tick resolves twice) — key alternation on `OutputIndex`.
- ffmpeg/ffprobe: `/mnt/c/Program Files/Krita (x64)/bin/` with Windows paths.
- `MyMistakes.md`: WINRT resource-allocation RECIPE, freeze-audit RECIPE, A/V sync recipe, deadline
pacing, CoreMessaging DQ, WGC-CLIP + slice blocks. Grep before re-deriving.
- **Test-host crash (fixed):** GC'd `WinEventProc` — `Shutdown()` unhooks the foreground-event hook;
never re-introduce `StartWatching` without matching teardown; dialogs with root-relative `/Assets/…`
Icon can't be instantiated by tests (use `/ytLive;component/…`).
- **Scene.Elements layer tests:** any seeded scene with `HasBackground=1` loads a healed
`Background` element pinned at `Elements[0]` (created by `EnsureBackground` on `StagedScene` set) —
compute expected layer orders from the live collection, never hardcode indices.
- **Cross-type element order tests** must assert through a FRESH `LayoutStore` (the restart), not the
running app's store — that's the read-back path the builder's bug exercised.
- `C:\tmpout` is for ffmpeg evidence artifacts; keep them out of the repo.
## Next step
The ordering fix is the builder-facing half of the "webcam between sources" bug — a manual take
(relaunch, live view, drag Web Resource-0 below the webcam, restart, expect it pinned there) closes
it. Then the copy with the builder on any remaining repro, then decide push. TASK 37 (defaults vs
current) and the build-id-on-exit demand are queued for a later slice — do not fold them in here.