soulsync/tests/downloads
Broque Thomas 45ecf2730d Wishlist: harden Spotify backfill — poisoned tn=1 can't mask lean album
Residual per-track wishlist downloads (single tracks from different
albums, below the album-bundle threshold) were producing folders
without a year subfolder whenever the wishlist row carried a stale
``track_number=1`` from an older payload default.

Why: ``core/downloads/candidates.py`` had a single API-fetch branch
that served two concerns — resolving the track position AND
hydrating the lean ``spotify_album_context`` (release_date /
total_tracks / cover image) — gated entirely on track_number being
unresolved. When the wishlist row's ``track_number`` happened to
be 1 (a poisoned default rather than a real value), the gate
short-circuited and the album hydration the same call would have
done was skipped. Deezer-sourced discovery matches don't ship
release_date in their search-result album shape, so without the
backfill the folder lost its year.

The two concerns split:
  - track_number resolution keeps its track_info → track object →
    API precedence chain. track_info defaults still win.
  - album hydration runs whenever release_date or total_tracks are
    missing, independent of where (or whether) track_number was
    resolved.

The single API round-trip still serves both — the cost contract
is preserved. The side-effect coupling is gone.

Lifted into ``core/downloads/track_metadata_backfill.py``
(``hydrate_download_metadata``) so the precedence chain is pinned
in isolation. 24 unit tests cover the precedence chain, the
poisoned-tn=1 regression case, defensive non-dict/None inputs,
the cost guard (API called at most once per invocation), and
disc_number resolution.

Also lands the upstream piece: ``core/wishlist/routes.py:_build_track_data``
no longer defaults ``track_number=1`` / ``disc_number=1`` /
``total_tracks=1`` / ``release_date=''`` when the library-modal add
payload omits them. Missing values now flow through as ``None`` so
the downstream pipeline can detect-and-recover instead of locking
to a fake position.
2026-05-27 16:47:26 -07:00
..
__init__.py PR4a: lift sync history recording to core/downloads/history.py 2026-04-27 20:37:16 -07:00
test_background_download_worker.py Add 5 test additions JohnBaumb suggested 2026-05-05 13:04:18 -07:00
test_deezer_pinning.py Surface engine-not-wired errors + exclude soulseek from monitor aggregation 2026-05-05 12:20:51 -07:00
test_download_engine.py Add 5 test additions JohnBaumb suggested 2026-05-05 13:04:18 -07:00
test_download_orchestrator.py Fix Usenet settings reload without restart 2026-05-22 08:28:56 -07:00
test_downloads_cancel.py PR4b: lift cancel + clear download routes to core/downloads/cancel.py 2026-04-27 21:41:35 -07:00
test_downloads_candidates.py Trust user manual picks past AcoustID verification (#701) 2026-05-26 09:56:49 -07:00
test_downloads_cleanup.py PR4c: lift _automatic_wishlist_cleanup_after_db_update to core/downloads/cleanup.py 2026-04-27 22:23:41 -07:00
test_downloads_history.py PR4a: lift sync history recording to core/downloads/history.py 2026-04-27 20:37:16 -07:00
test_downloads_lifecycle.py Add torrent and usenet release staging support 2026-05-21 14:22:21 -07:00
test_downloads_master.py Harden album bundle fallback flow 2026-05-24 16:15:36 -07:00
test_downloads_post_processing.py Add torrent and usenet release staging support 2026-05-21 14:22:21 -07:00
test_downloads_staging.py Fix album-bundle staging match + wishlist provenance (#700, #698) 2026-05-26 07:12:49 -07:00
test_downloads_status.py Wishlist: distinguish Queued from Analyzing for executor-pending batches 2026-05-27 14:52:02 -07:00
test_downloads_task_worker.py Add Soulseek album bundle downloads 2026-05-23 15:08:21 -07:00
test_downloads_validation.py Add torrent and usenet release staging support 2026-05-21 14:22:21 -07:00
test_hifi_pinning.py Support legacy HiFi track manifests 2026-05-21 18:11:14 -07:00
test_lidarr_pinning.py A8: Pin LidarrDownloadClient download lifecycle behavior 2026-05-04 12:10:49 -07:00
test_qobuz_pinning.py Surface engine-not-wired errors + exclude soulseek from monitor aggregation 2026-05-05 12:20:51 -07:00
test_rate_limit_policy.py E1: Add RateLimitPolicy declaration mechanism 2026-05-04 14:38:20 -07:00
test_soulseek_pinning.py Add Soulseek album bundle downloads 2026-05-23 15:08:21 -07:00
test_soundcloud_pinning.py Surface engine-not-wired errors + exclude soulseek from monitor aggregation 2026-05-05 12:20:51 -07:00
test_tidal_pinning.py Handle non-JSON Tidal auth responses 2026-05-20 14:04:45 -07:00
test_track_metadata_backfill.py Wishlist: harden Spotify backfill — poisoned tn=1 can't mask lean album 2026-05-27 16:47:26 -07:00
test_wishlist_aggregator.py Wishlist modal: surface most-advanced live phase, not least-complete 2026-05-26 22:35:53 -07:00
test_youtube_pinning.py Surface engine-not-wired errors + exclude soulseek from monitor aggregation 2026-05-05 12:20:51 -07:00