soulsync/core/automation
Broque Thomas cde237c7e7 Extract automation handlers (2/N): playlist lifecycle group
Continues the lift from `web_server._register_automation_handlers`.
This commit extracts the four playlist-lifecycle closures:

- `refresh_mirrored`   -> core/automation/handlers/refresh_mirrored.py
- `sync_playlist`      -> core/automation/handlers/sync_playlist.py
- `discover_playlist`  -> core/automation/handlers/discover_playlist.py
- `playlist_pipeline`  -> core/automation/handlers/playlist_pipeline.py

The pipeline composes refresh + sync + discover, so all four ship
together. The pipeline imports the other three handler modules
directly (cross-handler call) instead of going through the engine,
preserving the "single trigger from the user's perspective" UX.

`AutomationDeps` grew to cover the new dependency surface:
- run_playlist_discovery_worker, run_sync_task, load_sync_status_file
  (pre-existing background-task entry points)
- get_deezer_client, parse_youtube_playlist (per-source clients)
- get_sync_states (live mutable accessor for the sync UI's state dict)

`web_server._register_automation_handlers` now wires those plus the
existing infrastructure into a single `AutomationDeps` and calls
`register_all`. The 669-line block of closure definitions and engine
register calls (lines 959-1627 pre-edit) is gone -- the file shed
743 lines net on this commit.

`tests/automation/test_handlers_playlist.py` adds 17 new boundary
tests:
- discover_playlist: no_id error, specific_id starts worker, all=True
  enumerates, no playlists in db
- refresh_mirrored: error path, source filter (file/beatport excluded),
  Spotify happy path with auto-discovered marker, per-playlist
  exception captured into errors counter
- sync_playlist: no_id, not_found, no_tracks, no-discovered-tracks
  skip, discovered-track happy path, unchanged-since-last-sync skip
- playlist_pipeline: no_playlist clears running flag, no-refreshable
  clears running flag, exception clears running flag

3223 tests pass. web_server.py: 35,593 -> 34,850 lines (743 removed).
2026-05-15 10:47:46 -07:00
..
handlers Extract automation handlers (2/N): playlist lifecycle group 2026-05-15 10:47:46 -07:00
__init__.py Extract automation handlers (1/N): infrastructure + 3 simple handlers 2026-05-15 10:25:41 -07:00
api.py Lift /api/automations/* into core/automation/ 2026-04-27 18:05:14 -07:00
blocks.py Lift /api/automations/blocks static config into core/automation/blocks.py 2026-04-27 18:31:36 -07:00
deps.py Extract automation handlers (2/N): playlist lifecycle group 2026-05-15 10:47:46 -07:00
progress.py Surface silent exceptions across remaining modules — ~70 sites 2026-05-07 10:28:58 -07:00
signals.py Add module logger + surface silent exceptions in 7 logger-less files — 12 sites 2026-05-07 10:27:04 -07:00