TASK 21 Increment A: media-source model + persistence (schema migration + round-trip test)

SourceType.MediaSource added; MediaSourceType (Video/Audio) and MediaPlaybackState
(Stopped/Playing/Paused) enums. Source gains MediaPath, MediaIsLooping, MediaVolume
(0-1 clamped), MediaPlaybackState. LayoutStore: MigrateSourceTable adds 4 guarded
ALTERs (MediaPath, MediaIsLooping, MediaVolume, MediaPlaybackState); SELECT appends
indices 26-29, INSERT adds 4 columns + params. Round-trip test
MediaSource_Config_Survives_Save_And_Reload passes. Build 0 warnings, 245/247
tests (2 known pre-existing). Gated on creator run for later integration (ffmpeg).
This commit is contained in:
2026-08-29 09:43:29 -07:00
parent 46f4696db6
commit eba6af5b9b
5 changed files with 188 additions and 65 deletions
+37 -57
View File
@@ -2,75 +2,55 @@
## Branch / Commit State
**`main`**, **working tree CLEAN.** TASK 18 (record-only pipeline + top-bar pills/light/Start-End button UX
+ Sign In label/spacing) **plus** the memory-map/derived-solution fix **and** the README hero image were
committed and pushed as **`a9eb360`** (2026-08-29). `origin/main` and head both at **`a9eb360`**.
**`main`**, last pushed commit **`46f4696`** (manual-rename modal). Working tree is **DIRTY** —
TASK 21 Increment A (model + persistence for media sources) is fully implemented, verified, and
ready to commit. See "In flight" below.
No feature branches pre-1.0: all work lands on `main` per work unit.
## Memory-map corrections (2026-08-29 — "don't re-derive" fix)
## In flight: TASK 21 — next bounded slice = Increment B (FFmpeg video decoder, items 4–5)
- **Incident:** the image-shrink recipe (for `docs/ytLlive-preview.jpg`) was never recorded when first
done, so it was re-derived from scratch. Fixed by:
- **`AGENTS.md`** → Working rules: new **🔬 Derived-solution rule** (record a one-off solution in
`MyMistakes.md` the same session; grep it first on any "did this before?" wall).
- **`MyMistakes.md`** → contract expanded: per-task failure log **+ RECIPES REGISTRY** (permanent, NOT
truncated); recorded the verified image-shrink recipe.
- **`schema.md`** → file inventory now rows `MyMistakes.md` as the recipes registry.
- **`ai.md`** → Derivative-work section notes the derived-solution rule (registry reachable from map home).
- **`README.md`** + `docs/ytLlive-preview.jpg` → README hero image replaced (screenshot downscaled to
1400×794, 188KB JPEG).
**What is DONE (uncommitted, ready to commit):** Increment A — `SourceType.MediaSource` enum,
`MediaSourceType`/`MediaPlaybackState` enums, media config fields on `Source` (`MediaPath`,
`MediaIsLooping`, `MediaVolume`, `MediaPlaybackState`), LayoutStore migration + SELECT + INSERT,
round-trip test (`MediaSource_Config_Survives_Save_And_Reload`). Build 0 warnings, 245/247 tests
(2 known failures), scope check clean.
**What is NOT started (Increment B):** `MediaVideoDecoder` — FFmpeg-based video decoder → `VideoFrame`.
Needs ffmpeg present on Windows PATH or in `%APPDATA%\ytLlive\tools` to test. Currently absent:
neither `ffmpeg.exe` on PATH nor in tools cache (locator's network pull hasn't run). This is a
**run-the-app wall** — not blocked from writing the code, but blocked from headless integration
testing. Can be shipped as a compile-verified code commit gated on creator run, or deferred until
ffmpeg is present.
## TASK 18 — Local recording (shipped `a9eb360`, 2026-08-29)
**Shipped (committed + pushed):**
- `EncoderOptions` + `FfmpegArgs` + `FfmpegEncoder`: independent `StreamEnabled`/`RecordEnabled`/
`RecordPath`; per-output blocks (`-f flv` stream, `-f mp4` record); encoder throws unless ≥1 output.
- `MainViewModel`: REC + ON-AIR pill toggles, status lights, dynamic `PrimaryButtonText`
(Start Streaming / Start Recording), `ShowPrimaryStartButton`/`ShowLogInButton`/`ShowEndStreamButton`,
`CanStartSession`, `AccountStatusLightToolTip`; `IsEditMode` += `!IsRecording`.
- `StartSession()` routes: ON-AIR → GoLive dialog then stream (± record); only-REC → `BeginRecordOnly()`
(no YouTube dialog). `StopStream()` no longer signs the creator out (explicit logout only) and runs
**rename-on-stop** to `ty-<yyyymmdd>-<HHmm start>-<hh2mm2 length>.mp4`.
- `Services/RecordingFile` (pure): auto-name `ty-…-0000.mp4` → rename-on-stop with hh2mm2 length.
- `LayoutStore.Load/SaveRecordFolder` + `ChooseRecordFolderCommand` (`OpenFolderDialog`), default
`%APPDATA%\ytLlive\recordings\`.
- `MainWindow.xaml`: REC/ON-AIR pill `ToggleButton`s + status lights, dynamic button, status-light tooltip,
About overlay border 520→650 / MaxHeight 560→700 / padding 24→28, About grid background `#171928`.
- Tests: `FfmpegEncoderTests` record-only + dual-output arg tests; `RecordingFileTests` (naming rules).
**Not done / parked:** manual rename dialog for the user (planned as a modal, needs a trigger since the
toast service has no actions) — parked; running-app verification of rename + dual output.
## Key facts / landmines
## Landmines (unchanged)
- **Pre-existing test failures (do not chase):** `AudioPipelineTests.Mix_HonorsProviderGains…` +
`RoundClipInteractionTests.Round_Clip_Corner_Is_Grabbable…` — fail on `main` with this change unapplied.
All other tests pass (incl. the 7 new recording tests).
`RoundClipInteractionTests.Round_Clip_Corner_Is_Grabbable…`.
- **App running locks `ytLive.exe`** → build fails MSB3027 until the creator exits the app.
- **Startup diagnostics:** `%APPDATA%\ytLlive\startup.log` (`Helpers/AppLog.cs`).
- **Real-MainWindow tests MUST set `LayoutPathOverride`** — DB pollution wiped real data once.
- **Good Dog Rule:** ONE integration test per change; no feature branches pre-1.0.
- **Scope Lock:** declared list below; run `scripts/scope-check.sh` before committing.
- **Every feature change ships memory updates in the SAME commit** — `TASKS.md` status + this file.
- **Pre-commit gate:** run `./scripts/verify.sh <scope...>` — clean build (0 warnings) + full tests + scope check. Do NOT trust an incremental build's "0 warnings".
- No `CODING.md`; conventions live in `AGENTS.md` + `ai.md`.
- **Pre-commit gate:** run `./scripts/verify.sh <scope...>` — clean build (0 warnings) + full tests +
scope check. Do NOT trust an incremental build's "0 warnings".
- **Good Dog Rule:** ONE integration test per change.
- **🔬 Derived-solution rule:** record one-off solutions in `MyMistakes.md` recipes registry same session.
- Startup diagnostics: `%APPDATA%\ytLlive\startup.log`.
- Media-source feature is large (12 items); each later slice (decode, compositor wiring, loop/volume,
UI) is its own bounded increment — decoder needs ffmpeg present, can't be headless-tested unless
ffmpeg is installed (currently absent from Windows PATH + empty tools cache).
## Commit scope (declared)
## Todo state
`Services/Encoder/EncoderOptions.cs Services/Encoder/FfmpegArgs.cs Services/Encoder/FfmpegEncoder.cs
Services/Encoder/FramePump.cs Services/RecordingFile.cs Services/LayoutStore.cs
ViewModels/MainViewModel.cs MainWindow.xaml ytLive.Tests/FfmpegEncoderTests.cs
ytLive.Tests/FramePumpTests.cs ytLive.Tests/RecordingFileTests.cs
AGENTS.md TASKS.md ai.md HANDOFF.md MyMistakes.md schema.md README.md
docs/ytLlive-preview.jpg docs/ytLlive-preview.png(deleted)`
- TASK 18: fully shipped (`a9eb360` recording, `c8374bd` docs, `be529a4` verify.sh, `46f4696` rename
modal). Only remaining = **running-app verification** (creator must run the WPF app).
- TASK 21: Increment A (model + persistence) done and ready to commit. Increment B (ffmpeg decoder)
is the next bounded slice — compile-verifiable without ffmpeg, but integration test is walled.
- TASK 22 (audio sync offset): not started.
## Next steps
1. **Running-app verification** of TASK 18 (the one real gap): confirm rename-on-stop produces
`ty-…-<len>.mp4` and dual stream+record output actually works live. Requires the creator to run the app.
2. ~~Manual rename modal~~ **DONE** — `RenameRecordingDialog` (themed modal, pre-filled auto-stem,
OK/Enter / Cancel/Esc, invalid-char + empty = keep-auto validation) shown at finalize in
`FinalizeRecordingAsync`; reuses `YtTextBox`/`YtButton` styles.
3. Continue queue: TASK 21 media source, TASK 22 audio sync offset.
1. Commit + push Increment A (the code is ready, gates passed, TASKS/HANDOFF docs updated).
2. Commit + push the handoff correction (HANDOFF says done, not partial).
3. Running-app verification of TASK 18 rename/dual-output (creator) — one of two run-app walls.
4. Increment B: write `MediaVideoDecoder` (FFmpeg → BGRA8 `VideoFrame`), compile-verified, gated on
creator run for integration test (ffmpeg not present headlessly).
5. Later TASK 21 slices + TASK 22.