Fix four quality-replacement bugs found by code re-audit
C1/C4: Cap blur-score computation at 1440 px before calling assess_quality so scores are always on the same Laplacian scale as the embedding path (which operates on Immich preview thumbnails). Also converts the image to RGB before scoring and stores 0.0 on assess_quality failure so files uploaded without a score remain eligible for future quality replacement instead of occupying a slot permanently. C2: Fall back to the tracker's mapped-filename set as the pre-upload baseline when the Frigate GET /api/faces endpoint is unreachable at upload start. Previously, uploads that succeeded during a partial API outage were never mapped in frigate_files, leaving get_tracked_frigate_file_count permanently under-counting those files and allowing Frigate to exceed MAX_AUTO_IMAGES over time. C3: Track min_quality_score_for_slot when a quality-replacement delete succeeds but the subsequent upload fails. This ensures the freed slot can only be filled by a candidate that beats the deleted file's score, not just the next file in iteration order (which could be lower quality than what was deleted). Add get_tracked_frigate_filenames() to upload_tracker and expand tracker tests to cover the new function and exclude-parameter behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -156,3 +156,65 @@ def test_get_lowest_quality_mapped_file_skips_unscored():
|
||||
result = get_lowest_quality_mapped_file("Alice")
|
||||
assert result is not None
|
||||
assert result[1] == "asset-scored" # only scored file is a candidate
|
||||
|
||||
|
||||
# ── get_tracked_frigate_filenames ─────────────────────────────────────────────
|
||||
|
||||
def test_get_tracked_frigate_filenames_empty():
|
||||
from winnow.upload_tracker import get_tracked_frigate_filenames
|
||||
assert get_tracked_frigate_filenames("Alice") == set()
|
||||
|
||||
|
||||
def test_get_tracked_frigate_filenames_returns_mapped():
|
||||
from winnow.upload_tracker import get_tracked_frigate_filenames, record_frigate_file
|
||||
record_frigate_file("Alice", "Alice-1000.webp", "asset-a")
|
||||
record_frigate_file("Alice", "Alice-1001.webp", "asset-b")
|
||||
assert get_tracked_frigate_filenames("Alice") == {"Alice-1000.webp", "Alice-1001.webp"}
|
||||
|
||||
|
||||
def test_get_tracked_frigate_filenames_excludes_removed():
|
||||
from winnow.upload_tracker import (
|
||||
get_tracked_frigate_filenames,
|
||||
record_frigate_file,
|
||||
remove_frigate_file,
|
||||
)
|
||||
record_frigate_file("Alice", "Alice-1000.webp", "asset-a")
|
||||
record_frigate_file("Alice", "Alice-1001.webp", "asset-b")
|
||||
remove_frigate_file("Alice", "Alice-1000.webp")
|
||||
assert get_tracked_frigate_filenames("Alice") == {"Alice-1001.webp"}
|
||||
|
||||
|
||||
def test_get_tracked_frigate_filenames_isolated_by_person():
|
||||
from winnow.upload_tracker import get_tracked_frigate_filenames, record_frigate_file
|
||||
record_frigate_file("Alice", "Alice-1000.webp", "asset-a")
|
||||
record_frigate_file("Bob", "Bob-2000.webp", "asset-b")
|
||||
assert get_tracked_frigate_filenames("Alice") == {"Alice-1000.webp"}
|
||||
assert get_tracked_frigate_filenames("Bob") == {"Bob-2000.webp"}
|
||||
|
||||
|
||||
# ── get_lowest_quality_mapped_file with exclude ───────────────────────────────
|
||||
|
||||
def test_get_lowest_quality_exclude_skips_specified_file():
|
||||
from winnow.upload_tracker import (
|
||||
get_lowest_quality_mapped_file,
|
||||
mark_uploaded,
|
||||
record_frigate_file,
|
||||
)
|
||||
mark_uploaded("asset-lo", person_name="Alice", score=0.10)
|
||||
mark_uploaded("asset-hi", person_name="Alice", score=0.90)
|
||||
record_frigate_file("Alice", "Alice-lo.webp", "asset-lo")
|
||||
record_frigate_file("Alice", "Alice-hi.webp", "asset-hi")
|
||||
result = get_lowest_quality_mapped_file("Alice", exclude={"Alice-lo.webp"})
|
||||
assert result is not None
|
||||
assert result[1] == "asset-hi" # lo was excluded; hi is returned
|
||||
|
||||
|
||||
def test_get_lowest_quality_exclude_all_returns_none():
|
||||
from winnow.upload_tracker import (
|
||||
get_lowest_quality_mapped_file,
|
||||
mark_uploaded,
|
||||
record_frigate_file,
|
||||
)
|
||||
mark_uploaded("asset-a", person_name="Alice", score=0.50)
|
||||
record_frigate_file("Alice", "Alice-a.webp", "asset-a")
|
||||
assert get_lowest_quality_mapped_file("Alice", exclude={"Alice-a.webp"}) is None
|
||||
|
||||
Reference in New Issue
Block a user