Files
LlamaCasty/MyMistakes.md
T
gramps 5ead064d54 fix(audio): _delayedMix never initialized — one NRE line behind the 'known failure', the class hang, AND the log flood; loopback gain now honest
The creator-declared known failure (Mix_HonorsProviderGains) and AudioPipelineTests'
standalone hang shared ONE root cause, born in TASK 22: AudioMixer.FillAndMix
dereferenced _delayedMix (declared float[]? , never assigned) as delayed.Length —
every live-mix tick NRE'd before the pipe write, so NO audio ever reached the wire
(tests starved -> hung/fail; app -> swallowed catch logged only ex.Message, 10ms
flood). Now: ctor-allocated + null-check, catch logs WITH stack via AppLog and is
throttled 5s, and a cancelled token breaks out before logging.

Bonus contract fix: AudioGainProvider.LoopbackGain returned unity on a disproven
premise ('loopback scales with endpoint volume'). The creator's tonight observation —
volume at 20%, meter pegged — proves the WASAPI tap is pre-endpoint-volume, so the
mixer must multiply by GameAudioVolume for stream honesty (this is what ai.md always
specified; the 'failing' test encoded the same and was RIGHT).

AudioPipelineTests: 25/25 in 26ms, standalone, no hang. Known-failure count: ZERO.
ai.md tests paragraph rewritten (no more suite-total claims, both ex-'knowns'
explained); TASK 22 regression recorded; MyMistakes: the known-failure-label rules.
2026-09-01 21:20:45 -07:00

149 lines
8.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.
# 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 `<UseWPF>true</UseWPF>`
(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 -- <path>` 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.