Status: completed Timestamp: 2026-04-01T00:30:00Z
- Added
table_exists, ensure_not_emptyto imports _keeper_sort_key:timesplayed→play_count_find_groups(artist-title): removed JOIN,FROM tracks,deleted = 0,path AS filepath,play_count_find_groups(filesize): removed JOIN,FROM tracks,deleted = 0,path AS filepath,play_count- Track dicts in both branches:
timesplayedkey →play_count groups_outputkeeper/duplicate dicts:timesplayed→play_countdedupe(): added wrong-DB guard +ensure_not_emptyat entryUPDATE library SET mixxx_deleted=1→UPDATE tracks SET deleted=1
- Added
table_exists, ensure_not_emptyto imports analyze_key(): added wrong-DB guard +ensure_not_emptyat entrycandidate_sql:FROM tracks,path AS filepath,deleted = 0, removedl.prefix, removed JOINcount_sql:FROM tracks,deleted = 0, removed JOINwhere_clause: removedl.prefix from column referencesUPDATE library SET key=?→UPDATE tracks SET key=?detect_keyand_write_taguntouched (pure audio, no schema refs)
test_dedupe_finds_duplicate_group— tracks 1 and 4 in same grouptest_dedupe_keeper_selection— track 1 wins (play_count=12 vs 1)test_dedupe_dry_run_no_write— no deleted=1 rows after dry-runtest_dedupe_apply_marks_duplicate— track 4 deleted=1, track 1 deleted=0test_dedupe_no_false_positives— tracks 2 and 8 not in any grouptest_dedupe_mode_field— dry_run / apply
test_analyze_dry_run_returns_candidates— 5 tracks without keytest_analyze_dry_run_no_write— no keys writtentest_analyze_force_includes_keyed— all 9 active tracks when force=Truetest_analyze_apply_writes_key— mocked detect_key("11B") written to DBtest_analyze_limit— assertsresult["processed"] == 2(not total_candidates, which is unaffected by LIMIT)test_analyze_mode_field— dry_run
test_analyze_limitassertsresult["processed"]notresult["total_candidates"]: LIMIT only caps the fetched rows, total_candidates is always the full unfiltered countlibrosais lazily imported insidedetect_key(), sofrom multidj.analyze import analyze_keyis safe without librosa; the try/except import guard in test_analyze.py is a belt-and-suspenders precaution- Wrong-DB guard in
dedupe()opens a separate guard connection before calling_find_groups()(which opens its own connection)
- New tests: 12/12 pass
- Full suite: 73/73 pass (no regressions)
Nothing — task complete.