Add transparent library health engine

This commit is contained in:
Philip Guzman
2026-06-30 17:47:54 -07:00
parent 167f029c28
commit b8bf9ec6e1
6 changed files with 155 additions and 1 deletions
+43
View File
@@ -0,0 +1,43 @@
from collections import Counter
from serato_doctor.matching import MatchingEngine
from serato_doctor.models.health import HealthReport
from serato_doctor.models.library import Library
def analyze_health(library: Library) -> HealthReport:
"""Calculate defensible health metrics without changing the library."""
results = library.reconcile_by_filename()
missing = [result for result in results if not result.exists_by_filename]
healthy_count = len(results) - len(missing)
score = (
round(healthy_count / len(results) * 100, 1) if results else None
)
disk_name_counts = Counter(track.filename for track in library.tracks)
duplicate_counts = [count for count in disk_name_counts.values() if count > 1]
referenced_names = {reference.filename for reference in library.references}
unused_count = sum(
1 for track in library.tracks if track.filename not in referenced_names
)
matcher = MatchingEngine(library.tracks)
suggested_count = sum(
bool(matcher.candidates_for(result.reference)) for result in missing
)
return HealthReport(
score=score,
total_references=len(results),
healthy_references=healthy_count,
missing_references=len(missing),
unique_missing_filenames=len(
{result.reference.filename for result in missing}
),
disk_tracks=len(library.tracks),
duplicate_filename_groups=len(duplicate_counts),
duplicate_files=sum(count - 1 for count in duplicate_counts),
unused_tracks=unused_count,
suggested_matches=suggested_count,
)
+2
View File
@@ -1,4 +1,5 @@
from serato_doctor.models.crate import Crate
from serato_doctor.models.health import HealthReport
from serato_doctor.models.library import Library
from serato_doctor.models.match import MatchEvidence, TrackMatch
from serato_doctor.models.reference import ReferenceResult, TrackReference
@@ -7,6 +8,7 @@ from serato_doctor.models.track import DiskTrack
__all__ = [
"Crate",
"DiskTrack",
"HealthReport",
"Library",
"MatchEvidence",
"ReferenceResult",
+22
View File
@@ -0,0 +1,22 @@
from dataclasses import dataclass
from typing import Optional
@dataclass(frozen=True)
class HealthReport:
"""Transparent aggregate findings from a read-only library analysis."""
score: Optional[float]
total_references: int
healthy_references: int
missing_references: int
unique_missing_filenames: int
disk_tracks: int
duplicate_filename_groups: int
duplicate_files: int
unused_tracks: int
suggested_matches: int
@property
def score_basis(self) -> str:
return "Resolved crate references / total crate references"