Restore household colours on the cold-start profile picker #70

Merged
justinzeus merged 1 commit from fm/tv-picker-colors into fm/tv-round2 2026-11-07 23:41:28 +01:00
Owner

Outcome

Saved profiles immediately show their approved household colours on cold start, without waiting for Conductarr: Justin blue (#62c4ff), Mindel orange (#ff9d72), Shared green (#9be38f).

Cause

app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinSetupViewModel.kt:83 constructed cold-start setup people with the Jellyfin UUID as ShellPerson.key. wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Identity.kt:17-21 resolves fixed household colours by justin/mindel/shared, so every UUID fell through to the lilac accent. The regular saved-people reader (ShellPeople.kt:19-22) and post-login completion already use lowercase names, explaining why the failure was cold-start-only. Conductarr's Person.kt:9-12 supplies only key/name, not an extra colour field; this was not cache colour loss and needs no cache/schema migration.

Change

Use the existing lowercase-name presentation identity in the setup picker while retaining jellyfinUserId unchanged for authentication. Document the cold-start colour invariant.

Verification

  • Added native Robolectric regression through the actual app-start/MainContent/setup interception path, with three locally saved people and no Conductarr session. It samples each rendered avatar fill.
  • Failed before: all three pixels were the lilac fallback instead of the three expected household colours.
  • Passed after: all four tests in the touched WolfskinSetupNavigationTest class, including the new native regression and existing startup/recovery/first-run paths.
  • Command: bash docker/gradle.sh debug :app:testDefaultDebugUnitTest --tests org.justinvisser.wolfskin.tv.WolfskinSetupNavigationTest -x :wolfskin-design:testDebugUnitTest (shared Gradle lock; design suite excluded).
  • Same-data native 1920×1080 frames and before/after JUnit reports: /root/.treehouse/firstmate-7bab20/2/firstmate/data/tv-picker-colors/before.png, after.png, before-test.xml, after-test.xml. Both frames visually inspected.
  • No TV/ADB access, emulator access, APK build or full-suite run.

Risk

Limited to the setup presentation key; saved credentials, Jellyfin selection IDs, palette tokens, Conductarr contracts and caches remain unchanged.

AI-assisted implementation and verification.

## Outcome Saved profiles immediately show their approved household colours on cold start, without waiting for Conductarr: Justin blue (#62c4ff), Mindel orange (#ff9d72), Shared green (#9be38f). ## Cause `app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinSetupViewModel.kt:83` constructed cold-start setup people with the Jellyfin UUID as `ShellPerson.key`. `wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Identity.kt:17-21` resolves fixed household colours by justin/mindel/shared, so every UUID fell through to the lilac accent. The regular saved-people reader (`ShellPeople.kt:19-22`) and post-login completion already use lowercase names, explaining why the failure was cold-start-only. Conductarr's `Person.kt:9-12` supplies only key/name, not an extra colour field; this was not cache colour loss and needs no cache/schema migration. ## Change Use the existing lowercase-name presentation identity in the setup picker while retaining `jellyfinUserId` unchanged for authentication. Document the cold-start colour invariant. ## Verification - Added native Robolectric regression through the actual app-start/MainContent/setup interception path, with three locally saved people and no Conductarr session. It samples each rendered avatar fill. - Failed before: all three pixels were the lilac fallback instead of the three expected household colours. - Passed after: all four tests in the touched `WolfskinSetupNavigationTest` class, including the new native regression and existing startup/recovery/first-run paths. - Command: `bash docker/gradle.sh debug :app:testDefaultDebugUnitTest --tests org.justinvisser.wolfskin.tv.WolfskinSetupNavigationTest -x :wolfskin-design:testDebugUnitTest` (shared Gradle lock; design suite excluded). - Same-data native 1920×1080 frames and before/after JUnit reports: `/root/.treehouse/firstmate-7bab20/2/firstmate/data/tv-picker-colors/before.png`, `after.png`, `before-test.xml`, `after-test.xml`. Both frames visually inspected. - No TV/ADB access, emulator access, APK build or full-suite run. ## Risk Limited to the setup presentation key; saved credentials, Jellyfin selection IDs, palette tokens, Conductarr contracts and caches remain unchanged. AI-assisted implementation and verification.
justinzeus added 1 commit 2026-11-07 23:38:53 +01:00
Restore household colours on the cold-start profile picker
All checks were successful
review/code-claude Code APPROVE: key change only, auth ids untouched
review/design-claude Design PASS: Justin blue, Mindel orange, Shared green
27b7554fc1
Author
Owner

Review of the cold-start picker colours fix at head 27b7554fc1489fbbb5e49720fe1d8707fd0a17f0 (base fm/tv-round2).

Code verdict: APPROVE (review/code-claude = success).
Design verdict: PASS (review/design-claude = success). No blocking finding, and no auth-path change.

Fix is at the cause.

  • The cold-start picker used the Jellyfin UUID as ShellPerson.key. personColor only knows justin, mindel and shared, so every UUID fell through to the lilac accent.
  • The key is now the lowercased name. That is what readShellPeople and the signed-in picker (WolfskinSetupViewModel.kt:178) already use.

Auth is unchanged.

  • jellyfinUserId = it.id.toString() is untouched.
  • select(person) still resolves the user by jellyfinUserId and then runs the same requireLogin, PIN and changeUser branches.
  • In my grep of the setup and app code, person.key is used only by the signed-in shell, where the lowercase-name key is already the norm. Nothing in setup maps a key back to a user id.

Colours.

  • A known household name never falls back to lilac, whatever its case.
  • Unknown or new users keep the default accent.

Test.

  • coldStartSavedPeopleKeepTheirOwnColorsWithoutConductarr goes through the real app-start and setup path.
  • It samples each rendered avatar fill and compares it with the palette tokens, asserts there is no Conductarr identity, and asserts the Jellyfin ids are the original UUIDs.
  • The stored results show it failing before (three lilac pixels) and the touched class passing after (4 tests, 0 failures).

Frames. Before: J, M and S are all lilac. After: Justin blue, Mindel orange, Shared green, with Justin focused. Heading, names, gear and positions are otherwise identical.

Merge. A merge-tree check against current fm/tv-round2 is clean.

Non-blocking notes:

  1. Two Jellyfin users whose names differ only by case, or an empty name, would now share a key. The signed-in picker has the same property, so this is consistency rather than a new risk.
  2. The key is derived from the display name, so renaming a user changes the colour. This matches the signed-in picker.

Full report (review 8): /root/.treehouse/firstmate-7bab20/2/firstmate/data/round2-review/report.md. Not run: Gradle/make, nothing on the box.

Review of the cold-start picker colours fix at head `27b7554fc1489fbbb5e49720fe1d8707fd0a17f0` (base `fm/tv-round2`). **Code verdict: APPROVE (`review/code-claude` = success).** **Design verdict: PASS (`review/design-claude` = success).** No blocking finding, and no auth-path change. **Fix is at the cause.** - The cold-start picker used the Jellyfin UUID as `ShellPerson.key`. `personColor` only knows justin, mindel and shared, so every UUID fell through to the lilac accent. - The key is now the lowercased name. That is what `readShellPeople` and the signed-in picker (`WolfskinSetupViewModel.kt:178`) already use. **Auth is unchanged.** - `jellyfinUserId = it.id.toString()` is untouched. - `select(person)` still resolves the user by `jellyfinUserId` and then runs the same `requireLogin`, PIN and `changeUser` branches. - In my grep of the setup and app code, `person.key` is used only by the signed-in shell, where the lowercase-name key is already the norm. Nothing in setup maps a key back to a user id. **Colours.** - A known household name never falls back to lilac, whatever its case. - Unknown or new users keep the default accent. **Test.** - `coldStartSavedPeopleKeepTheirOwnColorsWithoutConductarr` goes through the real app-start and setup path. - It samples each rendered avatar fill and compares it with the palette tokens, asserts there is no Conductarr identity, and asserts the Jellyfin ids are the original UUIDs. - The stored results show it failing before (three lilac pixels) and the touched class passing after (4 tests, 0 failures). **Frames.** Before: J, M and S are all lilac. After: Justin blue, Mindel orange, Shared green, with Justin focused. Heading, names, gear and positions are otherwise identical. **Merge.** A merge-tree check against current `fm/tv-round2` is clean. **Non-blocking notes:** 1. Two Jellyfin users whose names differ only by case, or an empty name, would now share a key. The signed-in picker has the same property, so this is consistency rather than a new risk. 2. The key is derived from the display name, so renaming a user changes the colour. This matches the signed-in picker. Full report (review 8): `/root/.treehouse/firstmate-7bab20/2/firstmate/data/round2-review/report.md`. Not run: Gradle/make, nothing on the box.
justinzeus merged commit 2c5e39261c into fm/tv-round2 2026-11-07 23:41:28 +01:00
Sign in to join this conversation.
No reviewers
No labels
exploring
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: justinzeus/wolfskin#70
No description provided.