Social bar v2: fediverse icons resolved via nodeinfo (with redirect-following), persisted software column, icon colors — 112 tests passing, 0 warnings

This commit is contained in:
2026-08-12 18:28:59 -07:00
parent db5fc06174
commit 9873eeda7d
18 changed files with 1878 additions and 321 deletions
+63 -14
View File
@@ -7,17 +7,66 @@
## Session state (last updated: 2026-08-12)
- **Finished:** Webcam resource validation (merged `e1d9e13`) + Social bar v1 (merged `8868f98`). 85 tests, 0 warnings. On `main`, pushed.
- **In flight:** Social bar UX is WRONG — the user was re-explaining what they actually want when ctrl+enter cut them off. The correction was NOT received. Do NOT continue the social bar until the user re-states their requirements. What I shipped vs. what they asked differs — they said "did you not understand what I asked for? It's pretty goddamn simple" but the message was lost.
- **What I shipped (may be wrong):** YT auto-add from connected account, two-box dialog (YT handle + URL/handle for other), service auto-detection from domain, fediverse `@user@domain` support, footer Social button + [+/-] on the LEFT under scenes/sources, meter centered under preview, colored initials badges (not real service logos).
- **What the user explicitly asked for (from their message before the cut-off):**
1. If creator is logged into YT, YT should be the first social by default (✅ done but UX may be wrong)
2. YT icon placemarker + text box asking for YT handle (I did auto-add — they may have wanted the placemarker + input flow instead)
3. Second box: URL or identifying string (`@gramps@llamachile.tube` is just as unique as a URL) (✅ done)
4. Pull the SERVICE logo, not the user's account logo, to represent the service (I used initials badges — they want actual brand logos)
5. Finding the user's account on the service validates the input (✅ done)
6. Socials bar should appear on the LEFT side of the volume control, centered under the scenes and sources listboxes (✅ done)
- **Something in this list is wrong** — the user said "did you not understand what I asked for?" but the correction was lost to ctrl+enter.
- **Landmine:** 19041 SDK projection gaps (Exclusive/DeviceLost not projected; CameraStreamState.Failed by int). The social dialog uses sync `.GetAwaiter().GetResult()` — fine for now. `HttpSocialValidator` hits real network — tests must fake it.
- **Next step:** WAIT for the user to re-state what they actually want for the social bar. Do NOT guess. Then fix it.
- **Secret/DB/port facts live:** OAuth client id/secret in `Helpers/OAuthCredentials.cs`; OAuth session token in `Helpers/TokenStore.cs` (DPAPI → `%APPDATA%\ytLlive\ytLlive.auth`); layout DB `%APPDATA%\ytLlive\ytLlive.db` (schema v7); OAuth callback `http://localhost:8765/oauth2/callback`; crash log `%APPDATA%\ytLlive\startup.log`.
- **Branch:** `main` (work UNCOMMITTED — see dirty list). Includes the previous
session's socials v2 fixes + this session's fediverse-service-icon work.
- **Finished this session (round 3):** user's live-test report said the mastodon
icon still didn't show for `@gramps@llamachile.tube`. Root cause: the identity
domain `llamachile.tube` is YunoHost-SSO-gated — `/.well-known/nodeinfo`,
`/@gramps`, and webfinger all answer with the SSO login page, so nodeinfo
returned nothing and the icon fell back to the honeycomb glyph. The real
instance lives at `mastodon.llamachile.tube`, and only the bare root
`https://llamachile.tube/` 302s to it ("default app" redirect). Fix:
`HttpSocialValidator.TryFetchFediverseSoftwareAsync` now, when nodeinfo on the
identity domain fails, follows the root redirect (`ResolveInstanceHostAsync`,
reads `resp.RequestMessage.RequestUri.Host`) and re-runs the nodeinfo lookup
on the resolved host. New test `FediverseHandle_RootRedirectToSubdomain_ResolvesSoftware`.
Build: **0 warnings**. Tests: **111 passing**.
- **What landed (all rounds this session):**
1. **Fediverse icon resolution**`DetectService` maps `@user@domain` to the
new `SocialService.Fediverse` (was `Link`/chain icon). On validate,
`HttpSocialValidator` best-effort GETs `https://{domain}/.well-known/nodeinfo`,
follows the first nodeinfo `links[].href`, reads `software.name`, and returns
it in `SocialLookupResult.FediverseSoftware`. `SocialEntry`/`SocialSlotViewModel`
carry `FediverseSoftware`; `SocialServiceIcons.LogoDataForFediverse(software)`
maps it to a bundled logo (mastodon/peertube/pixelfed/misskey/lemmy/pleroma/
firefish — Simple Icons CC0), falling back to the `FediverseIconData`
honeycomb glyph for unknown software (GoToSocial/Sharkey/Akkoma aren't in
Simple Icons). Nodeinfo failure still validates — the glyph falls back.
2. **Redirect resolution (round 3)** — identity domains that 302 their root
to the real instance (YunoHost default-app subdomains) resolve software via
the root redirect when identity-domain nodeinfo is SSO-blocked.
3. **Persistence** — new `SocialEntry.Software TEXT` column via
`MigrateSocialEntryTable()` (column-presence pattern, same as the others);
saved/loaded alongside Service/Handle/ProfileUrl.
4. **Icon colors**`IconButton` style gains `Foreground="#d0d0d0"`
(`Themes/Controls.xaml`); the dialog's trash button overrides
`Foreground="#e94560"` (`SocialsDialog.xaml`). All other `IconButton`
usages are `Path` content with explicit `Fill`, so unaffected.
- **Landmines:**
- `LayoutStore.Socials` is only populated by `Load()` — tests must call
`store.Load()` before asserting it.
- `DetectService("justaname")`**Website** with empty handle; only
unparseable input or `@user@domain` yields Link/Fediverse.
- Dialog sign-in provider is `Func<Task<YouTubeChannel?>>`; test fakes must
return `Task.FromResult` (sync-completed) so the fire-and-forget command
settles before the next assert.
- `SocialBarBottomTop = 1040` literal lives in `MainWindow.xaml.cs` (the VM's
`MasterFrameHeight` is private).
- `Cancel_AbortsInFlightValidation_WithoutMutatingSlot` relies on the
BlockingValidator's gate completing synchronously (no
`RunContinuationsAsynchronously`) — the assertions run after
`Gate.TrySetResult` returns because the awaited continuation executes inline.
- Nodeinfo cancellation test cancels mid-lookup via a counting stub; the
post-fetch `ct.IsCancellationRequested` check is what reports `Canceled`.
- Round-3 redirect fallback fires only when identity-domain nodeinfo fails;
the root follow happens automatically (HttpClient default auto-redirect),
and `RequestMessage.RequestUri.Host` is read from the final response.
- **Next step:** show the user the fixes and let them decide whether to commit.
Nothing queued beyond that — do not expand the task queue on your own.
(`ytLive.Tests`/`bin` + `/obj` are dirty build artifacts, not hand-authored.)
- **Secret/DB/port facts live:** OAuth client id/secret in `Helpers/OAuthCredentials.cs`;
OAuth session token in `Helpers/TokenStore.cs` (DPAPI → `%APPDATA%\ytLlive\ytLlive.auth`);
layout DB `%APPDATA%\ytLlive\ytLlive.db` (schema v8; the new `SocialEntry.Software`
column is a column-presence migration like the others, no version bump); OAuth callback
`http://localhost:8765/oauth2/callback`; crash log `%APPDATA%\ytLlive\startup.log`.