fix: 3 audit findings — truthy skip-reason bug, 500 match consistency, CHANGELOG note

1. if saved: → if isinstance(saved, tuple): so string skip-reasons from
   process_face_mode no longer register as successes and create phantom
   asset_map entries with no JPEG on disk. Dead reason/fallback code in
   the else branch now correctly handles str and None returns.

2. "could not process" permanent-rejection check now uses error_detail
   (json message field, falling back to body[:100]) instead of full_body,
   keeping the match consistent with what is displayed to the user.

3. CHANGELOG [Unreleased] breaking-change note for MAX_AUTO_IMAGES 20→5
   so upgrading users know to set the env var if they want the old cap.
This commit is contained in:
2026-06-17 17:31:20 +00:00
parent f6e494071e
commit 86caffc8d7
2 changed files with 7 additions and 4 deletions
+4
View File
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Changed
- **`MAX_AUTO_IMAGES` default lowered from 20 to 5** — existing users who have not set this variable and already have more than 5 winnow-managed images in Frigate will find themselves at cap on the next run. With `QUALITY_REPLACEMENT=true` (the default), winnow will attempt to swap weaker images rather than uploading new ones. Set `MAX_AUTO_IMAGES=20` to restore the previous behaviour.
## [0.6.5] - 2026-06-17 ## [0.6.5] - 2026-06-17
### Added ### Added
+3 -4
View File
@@ -186,12 +186,11 @@ def execute_jobs(jobs: list[dict]) -> None:
saved = process_face_mode( saved = process_face_mode(
img, asset, person, person_dir, count, insightface_app=insightface_app img, asset, person, person_dir, count, insightface_app=insightface_app
) )
if saved: if isinstance(saved, tuple):
filename = f"{count}.jpg" filename = f"{count}.jpg"
asset_map[filename] = asset["id"] asset_map[filename] = asset["id"]
score_map[filename] = asset.get("quality_score") score_map[filename] = asset.get("quality_score")
if isinstance(saved, tuple): dims_map[filename] = saved
dims_map[filename] = saved
# Time-spread path: compute blur score from the downloaded # Time-spread path: compute blur score from the downloaded
# image. Capped at 1440px via blur_score_from_image() so the # image. Capped at 1440px via blur_score_from_image() so the
# scale matches the preview thumbnails the embedding path uses # scale matches the preview thumbnails the embedding path uses
@@ -574,7 +573,7 @@ def upload_to_frigate(jobs: list[dict]) -> None:
_is_permanent = ( _is_permanent = (
(resp.status_code == 400 and "face" in full_body.lower()) (resp.status_code == 400 and "face" in full_body.lower())
or resp.status_code == 422 or resp.status_code == 422
or (resp.status_code == 500 and "could not process" in full_body.lower()) or (resp.status_code == 500 and "could not process" in error_detail.lower())
) )
if _is_permanent: if _is_permanent:
asset_id = asset_map.get(fname) asset_id = asset_map.get(fname)