main's JS suite has been red since the recent v3-library and player
refactors landed. 17 of 18 failures were test harnesses/regexes that
went stale behind real, intentional code changes; one was a genuine
contract violation in the code.
Code fix:
- session-resume seek passed 'resume' as its _audioSeek reason; the
documented contract (enforced by song_seek.test.js) requires
multi-word kebab-case. Renamed to 'session-resume' — no consumer
string-matches specific reasons, so this is rename-safe.
Test updates (each pins the CURRENT contract):
- highway_colors_facade: inject HWC_PRESETS + applyHighwayStringPreset
(new preset feature); lock presets/applyPreset into the surface test
- loop_api: stub _updateEditRegionBtn (new edit-region UI hook)
- song_close: sandbox gets window.feedBack.playQueue; assert a real
close abandons the queue (the new queue-aware behavior)
- v3_keep_practicing: the shelf moved from client-side /api/stats/recent
dedupe+gating to the server-side practice-suggestions recommender —
tests now pin that (fetch, arrangement-aware card click, Promise.all)
- v3_songs_tuning: card row variable renamed song → shown (grouped cards)
- live_guitar_tone_source: accept literal ’ where ’ drifted in copy
- legacy_shim_hits: normalize CRLF before fixed-width region() slicing
(Windows-only failure; char windows shrank by one char per line)
Suite: 987/987 locally (Windows), previously 968/987 (and 18 red on CI).
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(v3 library): practice-aware home — Repertoire meter + "Keep practicing" shelf
The Songs page opened cold into a flat sorted grid. This adds a practice-aware
front door on the unfiltered grid, built entirely from data already on hand
(no new endpoints, no new stored state):
- Repertoire meter — "Repertoire: N of M songs · K in progress" + a bar,
counting songs at/above the same mastery threshold the green accuracy badge
uses (>= 0.9 best accuracy) over the unfiltered library total. Reads
state.accuracy (/api/stats/best, already loaded for the card badges) and the
unfiltered /api/library/stats total.
- "Keep practicing" shelf — a horizontal row of recently-played, not-yet-
mastered songs (newest first, click to play). Reads /api/stats/recent.
Both show ONLY on the grid view when not searching/filtering/selecting (the
front-door context), refresh after a song is scored (applyScoreRefresh), and
collapse on an empty library. Soft-gamification only: descriptive encouragement
(goal-gradient / endowed-progress), never content-gating, decay, or nagging —
the practice-accuracy "continue" rail a media server can't do.
Frontend-only: static/v3/songs.js (renderLibraryHome / _repertoireCounts /
libHomeVisible, wired through reload() + applyScoreRefresh), static/v3/v3.css.
Came out of the library design charrette (UX + gamification lenses' top pick).
Stacked on the A–Z rail branch (feat/v3-library-az-rail) since both touch
static/v3/songs.js; merge that PR first (or retarget).
Tests: tests/js/v3_keep_practicing.test.js (threshold, front-door gating,
shelf filter, denominator, render/reload/score-refresh wiring, click-to-play).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbexxfTt8q2tAn436MqGWF
* fix(v3 library): correct practice-aware home for review P1/P2/P3
Addresses the PR #635 review findings (manual + Codex):
P1 correctness
- Gate the Repertoire meter + "Keep practicing" shelf to the LOCAL
provider (libHomeVisible). They read local practice stats
(state.accuracy / /api/stats/recent); on a remote provider they mixed a
local mastered count with a remote song total (e.g. "85 of 80") and the
shelf played local files while browsing a remote library.
- Shelf now gates on the per-SONG best (state.accuracy[filename] = MAX
across arrangements, what the green badge shows) and dedupes by filename,
instead of the per-arrangement recents row — so a "keep practicing" card
can no longer show a green "mastered" badge, and a song can't appear twice.
P2 robustness
- renderLibraryHome fetches /api/library/stats + /api/stats/recent together
(Promise.all) and a _homeToken generation guard discards a stale render
so a slow response can't repaint a home the grid already moved past.
P3 polish
- accuracyBadge references MASTERY_ACCURACY instead of a bare 0.9, so the
badge and the meter/shelf can't drift from "the same mastery threshold".
Tests updated (v3_keep_practicing.test.js): provider gating, per-song
deduped shelf, Promise.all + token.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: byrongamatos <xasiklas@gmail.com>