# MyMistakes.md
> **Two jobs**, distinguished by heading:
>
> 1. **Per-task failure log** β updated before every commit touching that task:
> current iteration + why the last one failed. On task complete, committed AND
> pushed β truncate to this stub. A new task does NOT seed this file until its
> first failure.
> 2. **Recipes registry** (DERIVED-SOLUTION RULE, see `AGENTS.md` π¬) β the durable
> home for one-off derived solutions, recipes, and how-tos. The moment you work
> out a reusable solution, write it here **in the same session**. GREP THIS FILE
> FIRST when you hit a "I've done this before but have to figure it out again"
> wall. Recipe entries stay permanently (they are NOT truncated on task
> completion) β only the failure log truncates.
## π¬ Recipes registry
### Shrink / re-encode an image for the README (screenshots β small hero image)
Worked out 2026-08-29 (the recipe was NEVER recorded the first time it was done, so
it had to be re-derived from scratch β that's the incident this entry exists to end).
**Approach:** a throwaway Windows-dotnet console app uses WPF's imaging stack
(`System.Windows.Media.Imaging`) β same framework the app runs on, zero NuGet
packages, high-quality downscale via `TransformedBitmap`. Screenshots compress
**far smaller as JPEG than PNG** (PNG 1400px = ~1.2MB; JPEG q82 1400px = ~188KB).
**Recipe (run via the Windows dotnet host from WSL):**
1. Create `imgresize.csproj` targeting `net8.0-windows` with `true`
(SDK controller). Put it in a Windows-visible temp path, e.g.
`C:\Users\gramp\AppData\Local\Temp\imgresize` β NOT `/tmp` (Windows dotnet can't
reach a Linux-only path reliably).
2. `Program.cs`: load `BitmapImage` (`CacheOption=OnLoad` β `Freeze()`), downscale
with `TransformedBitmap(src, new ScaleTransform(scale, scale))` to max width
(1400 for the README hero), encode with `JpegBitmapEncoder { QualityLevel = 82 }`,
save.
3. Run:
```bash
"/mnt/c/Program Files/dotnet/dotnet.exe" run -c Release --project .
-- "C:\Users\gramp\Downloads\Screenshot 2026-08-29 075626.png"
"C:\Users\gramp\Documents\Code\projects\ytLive\docs\ytLlive-preview.jpg" 1400
```
4. Point `README.md` at the `.jpg` (not `.png`).
**Result:** 3.2MB screenshot β 1400Γ794 β **188KB** `ytLlive-preview.jpg` in `docs/`.
---
## Splitting a large file into partials β NEVER `awk β¦ > SRC` while awking SRC
(2026-08-31, Commit D) Tried to split `SocialsDialogViewModel.cs` in one line:
`{ awk 'β¦' SRC; echo ""; awk 'β¦2β¦' SRC; } > SRC`. The **first write truncated
SRC to 1 line**, so the second `awk` read the already-truncated file β the whole
source was lost (1 line left). Recovered with `git checkout -- SRC`, then redid
it, but the same bug could have meant making it up from scratch.
**Rule:** when a cut needs N blocks from one source into N files, never write a
block back onto the source that the `awk`s still read. Instead:
1. Read the source **once** at the start into temp files (`mktemp -d`, one file
per block), with a `$D` variable you carry forward.
2. Verify block sizes (`wc -l`) and brace balance (`python3 -c` counting `{`/`}`)
before touching any real file.
3. Then assemble each new file from `cat D/block β¦` β never truncating the source
until every read is done.
`git status` can't save you here if you don't notice until the file is gone β
`git checkout -- ` from the last commit is the recovery. Cheap insurance:
restore-then-retry, do it atomically from temp files the first time.
---
## Verifying an ffmpeg decode contract from WSL (no real CLR needed)
(2026-08-31, TASK 21) When a change depends on ffmpeg producing output with an
exact frame-size contract (rawvideo WΓHΓ4 BGRA), you can prove the **command +
frame accounting** here without any .NET process:
1. Fetch a **static Linux ffmpeg** into `/tmp/opencode` (no sudo needed):
`curl -sLO https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
&& tar -xf β¦`
2. Generate a tiny known clip: `ffmpeg -f lavfi -i "testsrc2=duration=1:size=640x360:rate=30" -pix_fmt yuv420p clip.mp4`
3. Decode with **exactly the app's args**: `-f rawvideo -pix_fmt bgra -vf scale=640:360 -an`
4. Assert `total_bytes % (W*H*4) == 0` (python3) β exact integer frames, no pad.
**Why not a dotnet-spawned ffmpeg here:** the only CLR on this box
(`/home/gramps/bin/dotnet`) is a **Windows-bound shim** β `Process.Start` resolves
paths to `\\wsl.localhost\Debian\β¦` and throws "not a valid application for this
OS" when handed a Linux ELF ffmpeg. So never plan to have dotnet exec a Linux
ffmpeg here; verify the contract with shell/python instead, and leave the
CLRβreal-ffmpeg run to the native Windows suite.
## WPF hit-test truth in tests: `UIElement.InputHitTest`, NOT `VisualTreeHelper.HitTest`
(2026-09-01, the RoundClip "known failure" post-mortem β a failure the map carried as
"not a regression" for weeks without ever recording WHY.)
**The trap:** `VisualTreeHelper.HitTest(window, pt)` returned the window's
`WebViewHostPanel` overlay (`IsHitTestVisible="False"`, `Opacity=0`, ZERO children) for
EVERY point in the window β so a "corner is grabbable" assertion could never pass, and
it looked like a real interaction bug. The actual input pipeline (`UIElement.InputHitTest`,
what Mouse routing uses) correctly returned the element's Grid at elem-center/corner-in/
corner-exact and fell through to CanvasGrid just past the corner. The product was fine;
the TEST was probing an API that doesn't model input semantics.
**Rule:** any test asserting "where does a click land" uses `window.InputHitTest(pt)` +
`IsDescendantOf` β never `VisualTreeHelper.HitTest`.
**Diagnosis recipe (how the lie was caught in ~3 probe cycles, no guessing):** add a TEMP
probe `[Fact]` in the RealApp collection that hit-tests a spread of points
(elem-center / corner-in / corner-exact / corner-out / bg-center) and `Assert.Fail`s with a
composed dump: per-point VTH hit + `InputHitTest` hit + ancestor chain (`GetParent` walk
with `#Name`) + panel properties (`IsHitTestVisible/Opacity/children/actual size`) +
`TranslatePoint` origins. Run the class alone, read the message, delete the probe.
**Two sibling facts learned the same session (record-once):**
1. A UserControl owns its own XAML namescope β after extracting a region out of a window,
`window.FindName("InnerPart")` returns null; resolve the UserControl by its window-level
name, then `pane.FindName("InnerPart")`. And window-scope STYLES are invisible to a
UserControl's `StaticResource` at parse time β move such styles to `Themes/Controls.xaml`
(the app-scope rule exists for this).
2. Per-class `dotnet.exe vstest` from WSL DOES execute the RealApp/`MainWindow` tests fine
(they passed natively 2026-09-01) β only the FULL suite hangs (WASAPI startup). And the
test process shares `%APPDATA%\ytLlive\startup.log` with the real app: lines like
`camera 'test-camera' failed` are test noise, not DB state β to check pollution, query
the DB directly (`python3 sqlite3`, `SELECT DeviceId FROM Webcam`), not the log.
## A "known failure" label without a recorded cause = a bug on life support
(2026-09-01, the audio triple-take) One line β `_delayedMix` (nullable, added by TASK 22,
never initialized) dereferenced as `delayed.Length` β produced THREE symptoms that lived in
the map as two separate "pre-existing, do-not-chase" entries: (a)
`Mix_HonorsProviderGainsβ¦` "known failure", (b) `AudioPipelineTests` hangs when run at all
(a test reading a named pipe with no writer blocks β hung test β flaky test, it's a starved
producer), (c) startup.log flooded "Audio live loop error" every 10ms (the mixer loop caught
and logged only `ex.Message` β stack thrown away).
Rules derived:
1. NEVER label a test "known/pre-existing" without writing WHY (exception type + first app
frame). An unexplained known-failure is deferred archaeology that hardens into fog.
2. A test that waits on IPC + a producer whose output vanished are usually ONE bug β look
for the producer before blaming the test.
3. Catch-and-log-swallow of `ex.Message` hides root causes; log with stack (`AppLog.Write(ex,
...)`) and throttle (5s) instead of dropping or flooding.
Bonus: the "failing" test encoded the MAP's contract (`loopbackGain = GameAudioVolume`); the
code had drifted to unity on a disproven premise (loopback capture does NOT follow endpoint
volume β creator's 20%-volume/pegged-meter observation killed it). The test was right all
along β failing tests may be the last honest witnesses; interrogate, don't pardon.
## Feature provenance: record WHO asked and WHY, in the task entry itself
(2026-08-31/09-01, the SYNC slider scare) TASK 22's lip-sync slider surfaced on the preview rail and
the creator's reaction was "totally don't remember ordering that" β because the queue entry recorded
WHAT shipped (a slider, 0-500ms, a converter class) but not WHO asked (the creator, explicitly, for
OBS's delay-filter fix built natively). Eight days later his own request read like AI drift and nearly
got deleted. Rule: the moment a creator-driven feature is queued or shipped, its entry carries a
one-line provenance β *who asked, what triggered it* ("creator: OBS delay-filter lip-sync fix, native").
Features without attribution become roadmap orphans that get punted, removed, or re-litigated. Same
disease as an unexplained "known failure" label β a fact recorded without its reason is a future
argument.