diff --git a/App.xaml.cs b/App.xaml.cs index 0ba296a..8dceaa4 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -26,6 +26,9 @@ public partial class App : Application AppLog.Write(args.Exception, "Dispatcher unhandled exception"); AppLog.Write("App OnStartup begin"); + // Attribution (2026-09-04): every take must be traceable to the exact binary + // that produced it — the wordmark superscript shows this same id. + AppLog.Write($"Build {ytLive.Helpers.BuildStamp.Id} (compiled {ytLive.Helpers.BuildStamp.BuiltLocal})"); // Velopack auto-update bootstrap — checks for updates on startup and // applies them (the app restarts automatically if an update is found). diff --git a/Controls/TopBar.xaml b/Controls/TopBar.xaml index 54bff2b..232f24f 100644 --- a/Controls/TopBar.xaml +++ b/Controls/TopBar.xaml @@ -1,6 +1,7 @@ @@ -20,7 +21,10 @@ - + diff --git a/HANDOFF.md b/HANDOFF.md index 5347d6b..e3c71d5 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -44,11 +44,18 @@ RealApp boot-smoke. Scope-check passed. raster on message/config change, blit the cached frame every tick (OBS text-source pattern). Tests: `ChatOverlayLayerCacheTests` (the ONE, RealApp) + full regression green (62 across touched classes), clean build 0 warnings. -2. **Take 6 (user, ~30s record-only):** expect `≈300/300 frames per 5s, avg render ≤ ~10ms`. If - chat-burst drops one frame per message (avg fine but `n/300` sags during live chat): debounced - off-tick re-render is the next slice. If steady at ~300 with render <10 → recording saga - CLOSED, go Unit B (below). -3. **Unit B — the top bar + session logic (user spec 2026-09-04, decisions settled):** +2. **BUILD STAMP shipped (slice 4, same day):** take 6 came back 35-41ms — WORSE than take 5 — + and attribution was impossible (exe timestamp ≠ binary contents; incremental builds served + unverified exes). Every build now stamps a fresh GUID (`ytLive.csproj GenerateBuildStamp` → + `Helpers/BuildStamp`), shown as the wordmark superscript (build id) + `Build xxxxxxxx (compiled + ...)` in startup.log; stats report `avg render Xms (resolve Y)` so the hot half of the tick is + named. Tests `BuildStampTests` + `BuildStampDisplayTests` (real window, namescoped FindName). +3. **Take 7 (user, ~30s record-only):** FIRST read the superscript + startup.log Build line — the + take is meaningless without it. Expect slice 3 in any post-stamp build: `avg render ≤ ~10ms + (resolve ≪ render), ≈300/300`. If resolve dominates → resolver-side surprise (chat config thrash + / web frame); if blit dominates → measure the general-path element sizes. If chat-burst sags + `n/300`: debounced off-tick re-render slice. If clean → recording saga CLOSED, Unit B. +4. **Unit B — the top bar + session logic (user spec 2026-09-04 re-sent twice + decisions settled in Q&A):** - Two-line top bar. Line 1: center = REC + **LIVE** pills (text renamed from ON-AIR; pills become mutually-exclusive RADIOS — record-OR-stream ruling), right = avatar + **Login/Logout** button (no account status light). Line 2: centered primary **Start** (grayed while NO pill armed — @@ -67,6 +74,12 @@ RealApp boot-smoke. Scope-check passed. live is scary — confirmation allows back-out + testing up to go-live"). - Bottom-bar metrics init/maintain: `ResetHealth` + `HealthUpdated` exist — verify on take 6. - F6 "start/end" hotkey routes through `HandleHotkey` — check it honors the new grayed-Start gate. + - Login button text: "Login" (disconnected, LIVE pill greyed) → "Logout" (connected, avatar + appears left of it). The account status LIGHT is deleted per spec 2a. + - Primary button: grayed "Start" when NO pill armed (inverts 2026-09-01 rule — fix the map in + the landing commit); enabled when either armed; REC path = file dialog flow; LIVE path = + go-live after dialog confirm; becomes the Stop/End face while active (user's "Stop button + never active" complaint gets a hermetic test pinning visibility+CanExecute). - ONE integration test (hermetic): pills↔button state machine + record-path seam (an `internal static Func` override seam mirroring `RegistrarOverride` — never pop real dialogs in tests). diff --git a/MyMistakes.md b/MyMistakes.md index b5b131c..5911e24 100644 --- a/MyMistakes.md +++ b/MyMistakes.md @@ -213,3 +213,18 @@ one-line provenance — *who asked, what triggered it* ("creator: OBS delay-filt 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. + +## An un-attributed build invalidated three takes of a perf saga — stamp the binary + +(2026-09-04, takes 4–6) After each render-perf fix the creator "exed the code" and re-recorded, but +the exe timestamp ≠ binary contents (incremental builds reuse whatever compiles clean; a source edit +with no rebuild serves the OLD exe). Take 6 measured render WORSE than take 5 (35-41ms) and there was +no honest way to tell "the chat cache fix doesn't work" from "the fix was never running" — three +hours of diagnosis on an unattributable sample. Rule: if takes measure the app, EVERY build carries +an id and EVERY log line traces to it — `GenerateBuildStamp` (csproj) writes a fresh GUID per +compile (deliberately defeating incremental lies), the wordmark shows it as a superscript, startup.log +records `Build (compiled