ef043c14d4
On GameWonEvent, computes xp_for_win(time, used_undo) from solitaire_data, calls PlayerProgress::add_xp, and emits LevelUpEvent when the level changes. Persists atomically through the configurable storage path; ProgressPlugin::headless() disables I/O for tests. Introduces ProgressUpdate system set so future systems can run after progress mutations. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>