note identifier exercise + retire legacy playable_keyboard path
Created by: jedmund
Summary
Four commits adding the note_identifier scored exercise, migrating every prompt-mode lesson onto it, retiring the legacy playable_keyboard scored-exercise path, and sharpening a few pieces of surrounding UX.
-
fde3c5enote identifier: add scored exercise, retire legacy playable_keyboard exercise path. Newnote_identifiertype built on the ScaleBuilder pattern (flash-red/shake on wrong, flash-green/advance on correct,ScoringOverlaywrap). Homepage gets a tile before Scale Builder. Migrates 8 prompt-mode lesson exercises (1-1 through 1-6 and 2-1), moves "Seven from Twelve" toscale_buildervia its existingguided_sequencesupport, and drops "Blues Playground" from the scored list. Lesson 1-1 configs gain bold-markdown prompt names; ex2 grows from 8 to 10 prompts so every black key is covered twice. RetiresPlayableKeyboardState,ExerciseStateRegistry.exerciseState(for:), thePageContainerlegacy branch, and theprompts/shufflePrompts/Promptfields onPlayableKeyboardConfig.ExerciseStateRegistrynow guards restoration against zero-total progress records (the old path could persisttotal=0and corrupt the restored state). -
dd72f71scoring overlay: render markdown answers, split two columns at 10+ prompts. Review rows parsePromptResult.answer(andcorrectAnswer) throughAttributedString(markdown:)so bolded note names render correctly. 10+ prompts split into two side-by-side columns so the card stays a reasonable height. -
332267fdocked keyboard: drop -200 background overextension. The docked keyboard's dark background had a-200ptnegative bottom padding to conceal the seam during the Playground slide-up animation. On lesson pages it was bleeding into the next page during scroll transitions. Removed. If the Playground seam returns, it can be concealed as a Playground-only modifier. -
399993fclaude.md: documentCurriculumRegistryas source of truth. Future agents kept assuminglessons/*.jsonis loaded at runtime (it isn't). The real curriculum structure lives insynthesize/synthesize/SampleData/CurriculumRegistry.swiftas a Swift literal, and that's whatCurriculumStorereads. Added this to the root CLAUDE.md andViews/Tools/CLAUDE.md's grep targets, and clarified which directories actually get loaded byContentLoader.
Test plan
-
Playground: Note Identifier tile appears before Scale Builder in the Exercises section. -
Launch it standalone: answer a few prompts, wrong taps flash red and shake, correct taps flash green and advance. Scoring card + retry works. Configurator sidebar toggles shuffle/accidentals/enharmonic/octave-range/total-questions and a restart respects them. -
Lesson 1-1 "Locating the Twelve" renders the new exercise with bolded prompt note names; completing it shows a 12-row single-column review with bold note names. -
Lesson 1-1 "Same Key, Two Names" shows 10 prompts; completion review splits into two 5-row columns. -
Lessons 1-2 ex1, 1-3, 1-4, 1-5, 1-6, 2-1 all render Note Identifier as their first-exercise slot. -
Lesson 1-2 "Seven from Twelve" runs as Scale Builder via guided sequence (C major scale ascending). -
Lesson 2-6 no longer lists "Blues Playground" as a scored exercise. -
Stale progress guard: a lesson-scoped activity with a legacy total=0record does not surface as "X of 0 correct"; the exercise plays fresh and overwrites the record on completion. -
Lesson scroll transitions: the docked keyboard's dark background no longer bleeds into the page below. -
Playground PlayableKeyboardtool still works (free-play + optional guided sequence); it no longer shows the old prompt/completion chrome.