CLAUDE.md gains backend/home and the two cross-cutting frontend pieces a list or detail view now has to know about: explore-link's always-navigate rule with its double-click grace, and <catalog-scope-notice> with the catalogPending/catalogLoaded distinction behind it.
4.3 KiB
006 — Orientation fixes: knowing where you are and what you're looking at
Status: implemented Branch: main Created: 2026-08-11 Follows: 005-agent-development-harness
Problem
Six reports from using the app, which turned out to be one theme with six faces: the UI knew things it did not say.
- Some track names in the track list were links, most were not. The rule (has both a release-group and a recording MBID) was invisible, so the list looked randomly broken.
- Opening an album sometimes showed the full catalog tracklist and sometimes only the tracks the user owned, with nothing on screen distinguishing the two — or distinguishing either from "still fetching".
- The same on artist pages: a discography that was the artist's, or a discography that was the user's shelf, rendered identically.
- "Check now" on the requests list appeared to do nothing, because it honoured each request's retry backoff — a request searched an hour ago was not due, so a deliberate button press produced silence.
- Pressing M muted playback and left the volume indicator
unchanged, because mute does not change the volume number and
VolumeChangedcarried nothing else. - The home page did not exist. The sidebar had a Home item; it fell through to "Coming soon: home".
What shipped
Backend
events.MuteChanged(bool), emitted alongsideVolumeChangedso the UI has something to react to when silence is the only thing that changed.Player.Muted()for symmetry;MuteTogglenow takes the speaker lock and refuses politely when no streamer exists.download.Reconciler.RunNow— a forced pass that ignores backoff, backed by a newListWantedDownloadRequestsquery.RunOnce(the loop) still honours it: the backoff is a promise to the providers, not to the user, and a person pressing a button is the schedule.SummarygainedWaitingandNoProvidersso "nothing happened" can be reported with a reason.backend/home— the shelf builder, with queries insql/queries/home.sqlthat return album ids only, joined back toGetAllAlbumsWithDetailsin Go rather than restating the album projection six times. A shelf with nothing behind it is omitted.
Frontend
explore-link.tsrewritten: a name always goes somewhere. No MBID means the library page for the same album/artist (both detail views already accept a local id), resolved through the library store, with an untagged track highlighted by title instead of by recording MBID. Links now fire on a genuine single click only — see below.<catalog-scope-notice>— one banner, four states (catalog,loading,library,unavailable), used by both detail pages. The album and artist pages grew an explicitcatalogPending/catalogLoadedpair, becauseloadingReleasesalready meant "something is renderable" and a library stand-in satisfies that.- Artist page: an empty
BrowseReleaseGroupsno longer wipes the library-hydrated discography — an empty catalog answer means "not indexed yet", not "released nothing". - Downloads: a no-client banner, per-request "next check in …", honest idle summaries, and copy that says the retry schedule exists.
<home-view>: shelves as horizontal rows; a cover opens the album, a play button plays it.
The one thing worth remembering
Making every track name a link broke double-click-to-play, and the
e2e playback suite caught it: the title is the widest thing in a row,
so the first click of the double-click landed on the link and navigated
away. Fixed in one place — singleClick() in explore-link.ts holds
the navigation for one double-click interval (250 ms) and drops it if a
dblclick arrives, while leaving the dblclick itself to bubble to the
row. Rows do not need to know links exist.
This is exactly the failure mode plan 005's e2e tier was built for; it was invisible before the change because the seeded fixture library has no MBIDs, so no track name was a link.
Verification
make lint (3 configs), make test (3 passes), make ui-test
(329 passing, up from 313), make e2e (23 passing, up from 19 — four
new home-page specs), tsc --noEmit, and manual verification of all
six items in the running app via make dev-headless + playwright-cli.