3a4e17c735
Creator on the live build: 'why do you make the youtube user icon go away?'
The TASK 42 one-surface bar had scoped the account zone to Stream only
('Record world has no YouTube identity at all'), so arming REC dropped the
avatar and the bar height bounced with it ('really fucking annoying').
Fix: ShowSignInButton / ShowAvatarButton are now plain !IsConnected /
IsConnected — app-level identity, present in both worlds, so the right
column never pops in/out and the bar height stays pinned. Test remains a
child of Stream (still stream-armed AND signed-in).
TopBarModeTests updated to the new contract: signed-out Record world shows
Sign In; flipping back to REC keeps the avatar. PillRadioTests untouched
(it only exercises the ON-AIR face). Docs corrected in-place (ai.md state
model, TASK 42 scope). Gate: clean build 0-warnings, 316/316, scope passed.
103 lines
6.9 KiB
Markdown
103 lines
6.9 KiB
Markdown
# HANDOFF — 2026-09-23 (build #77 feedback round; LOG fixes all shipped; app likely running)
|
||
|
||
## Branch / Commit State
|
||
|
||
`main` HEAD = **`d72949e`** (build-77 top-bar feedback: avatar/gear/cluster). Backlog:
|
||
`ac6e67a` (end close-out), `18ab553` (health-poll), `e69db4d` (TASK 42), `bb5dcb4` (TASK 41).
|
||
Pushed state at `197ee81` (36 commits ahead locally — push only at a sub-milestone / on the
|
||
user's say-so).
|
||
|
||
**Working tree DIRTY — account zone made world-independent (creator 2026-09-23):**
|
||
|
||
```
|
||
M ViewModels/MainViewModel.Streaming.cs (ShowSignInButton = !IsConnected, ShowAvatarButton = IsConnected)
|
||
M ytLive.Tests/TopBarModeTests.cs (REC-world asserts: avatar stays, Sign In visible signed-out)
|
||
M ai.md, TASKS/task-42, HANDOFF.md
|
||
```
|
||
|
||
Previous two hotfix units (audio-sync dot + YPP 403/statistics-string) are COMMITTED (`cb75066`);
|
||
top-bar feedback COMMITTED (`d72949e`).
|
||
|
||
## ⚠️ The account-zone unit (this turn)
|
||
|
||
Creator, clicking RECORD on the live build: "why do you make the youtube user icon go away?" — the
|
||
TASK 42 one-surface bar had scoped the account zone to the Stream world ("Record world has no YouTube
|
||
identity at all"), so arming REC dropped the avatar AND the bar height bounced with it ("really fucking
|
||
annoying"). Fix: `ShowSignInButton`/`ShowAvatarButton` are now world-independent (`!IsConnected` /
|
||
`IsConnected`) — the right column never pops in/out, bar height pinned. Test stays a child of Stream.
|
||
`TopBarModeTests` updated: signed-out Record world shows Sign In; flipping back to REC keeps the avatar.
|
||
|
||
## ⚠️ The app is RUNNING, and that's the story of this round
|
||
|
||
Ac6e67a **could not be verified through the normal gate** because the user was *looking at the
|
||
running app* (PID 17752) while it happened. `verify.sh` (clean build 0-warnings + full suite +
|
||
scope check) **cannot run until the app is closed** — an in-place build fails the `apphost.exe`
|
||
copy MSB3021/MSB3027 while the exe is locked. Compile gate used instead: `dotnet build` reaches
|
||
the copy stage with XAML/markup compiling clean (only the 2 copy errors → code + XAML are valid).
|
||
|
||
## What the user asked this round (live-launch feedback on #77, all XAML-only)
|
||
|
||
1. **Avatar** much bigger — now 40×40 (was 26), CornerRadius 20, initial 20pt. Shows the streaming
|
||
account at a glance (113% bigger than the old 26 read).
|
||
2. **Gear** moved further from the brand — margin 6 → 18 (a couple more "places").
|
||
3. **Uniform 32-height cluster in the top center** — segments host Border, Start/Go Live, and Test
|
||
all `Height="32"` so the REC|ON-AIR switch + its actions read as ONE family ("so the user can
|
||
intuit their purpose"). Running world (reality line) intentionally untouched. **[COMMITTED `d72949e`]**
|
||
4. **Audio-sync status light LOST** — `"AUDIO SYNC"` slider keeps its numeric tooltip; the green/
|
||
amber 8×8 dot was "what is the point" dead weight. `IntToSyncBrushConverter` + its resource +
|
||
TASK-22's "visual feedback" decision all retired with it, both docs updated in-place.
|
||
5. **YPP refresh bug (this turn, "Seriously?")** — `channels.list?mine=true&part=statistics,
|
||
auditDetails,contentDetails` 403'd `insufficientPermissions` on EVERY real refresh since slice 1
|
||
shipped: the **`auditDetails` part alone requires the `youtubepartner-channel-audit` scope**
|
||
(MCN partner tooling the app must never hold; the "no re-consent / scopes suffice" slice-1 claim
|
||
was wrong). Fix: part list is now `statistics,contentDetails`; standing flags dropped from
|
||
snapshot→VM→drawer in favour of an honest "not exposed to apps — check the Earn page" row;
|
||
`channels.list` failures now log the response body's `error.reason` (the bare code hid this for
|
||
days); new Good Dog `ChannelStatsServiceTests` guards no-auditDetails + still-parses — which it
|
||
then used to catch a SECOND latent bug the 403 masked (statistics are JSON strings; `GetInt64`
|
||
throws → now the tolerant `ReadInt64`, ValueKind-first). Docs:
|
||
ai.md / TASK-39 / TASKS.md / MyMistakes all corrected. Cite:
|
||
https://developers.google.com/youtube/v3/docs/channels/list
|
||
|
||
## What shipped before this round (all committed)
|
||
|
||
- **`ac6e67a` end-of-stream close-out fix** — every 2026-09-22 stop logged
|
||
`transition(complete) 403 invalidTransition`; the blind POST raced YouTube/autoStop marking the
|
||
broadcast complete (`enableAutoStop=true` always set). `EndBroadcastAsync` now pre-flights
|
||
`liveBroadcasts.list→status.lifeCycleStatus` and skips the POST when already complete/revoked;
|
||
inconclusive pre-check still posts (backstopped); never throws. Good Dog:
|
||
`EndBroadcast_Verifies_LifeCycle_Then_Transitions_Complete_Never_Throws` (3 halves: live→GET+POST,
|
||
complete→skip, 403→error-string). Cite: youtube liveBroadcasts/transition errors table. **Full
|
||
suite 315/315** (audio-timing flake `Mix_HonorsProviderGains…` cleared on rerun); verify.sh clean
|
||
pass predates this round's XAML-only edits.
|
||
- **`18ab553` health-poll fix** — `status.healthStatus` is an OBJECT, not a string; every session
|
||
start logged `requires an element of type 'String'`. Nested shape parsed (flat tolerated), banner
|
||
alive again.
|
||
- **TASK 42** (`e69db4d`) + **TASK 41** (`bb5dcb4`) — one-surface top bar, Test Stream drawer.
|
||
|
||
## Around the task (carried facts)
|
||
|
||
- RealMouseDrag test no-ops while a game/fullscreen window steals the mouse (POE 2 seen 2026-09-22)
|
||
— close games before full-suite runs. AudioPipeline timing flake similar (load-dependent).
|
||
- Test-env trap: saved OAuth session loads synchronously → force `vm.IsConnected` in signed-in tests.
|
||
- `subscriberCount` YPP slice 2 needs re-consent — do not merge with other units. Polar `$99/yr`
|
||
must become one-time before launch. `MARCOM.md`/`MONETIZATION.md` gitignored — never commit.
|
||
- The **`YppSnapshot.OverallGoodStanding` etc. columns now serialize false forever** (the API path
|
||
no longer populates them; schema kept stable for the analytics slice). Don't "restore" the
|
||
standing flags via auditDetails — see the MyMistakes recipe.
|
||
- TASK 40 App Settings round: units **A (camera) → C (defaults) → D (accent)** remain; A's
|
||
SharedReadOnly control-write question = only genuine uncertainty.
|
||
|
||
## Next step
|
||
|
||
1. **Run the gate on the account-zone unit** (declared scope: `ViewModels/MainViewModel.Streaming.cs`,
|
||
`ytLive.Tests/TopBarModeTests.cs`, `ai.md`, `TASKS/task-42-top-bar-redesign.md`, `HANDOFF.md`) —
|
||
`./scripts/verify.sh`: clean build 0-warnings + full suite + scope check. Then commit it
|
||
("account zone is world-independent — avatar stays in Record world", code + docs in one).
|
||
Repo is 36 commits ahead of pushed `197ee81`; push decision is the creator's (sub-milestone).
|
||
|
||
## Critical working rules (unchanged, still binding)
|
||
|
||
- **Good Dog = ONE integration test per change.** Scope lock + `./scripts/scope-check.sh` before commit.
|
||
- Windows dotnet host for all WSL builds (`/mnt/c/Program Files/dotnet/dotnet.exe`, quoted paths).
|
||
- 0 warnings on real clean builds (verify.sh only, never incremental). One runtime model. |