- FRIGATE_SCORE_THRESHOLD=0.0 now fully disables the quality gate including the
dynamic floor; a positive value is required to activate either
- Post-reconcile gate deletions are batched into one API call per person instead
of one call per file
- Per-person summary reports gate removals and net uploaded count when the gate
fires; grand summary includes total removed across all people
- .env.example comment updated to match the corrected opt-in behaviour
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
At the start of each person's upload phase, compute the minimum stored
Frigate recognition score across all currently mapped files. Use
max(config_threshold, dynamic_min) as the effective gate threshold so
new uploads must score at least as well as the weakest image already
in the training set.
Prevents overtraining well-recognised people: if all 80 images score
≥0.85, the dynamic threshold becomes ~0.85 and new additions that
score below that are removed rather than diluting a good training set.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When FRIGATE_SCORE_THRESHOLD > 0, images that score below the threshold
after upload are deleted from Frigate and removed from the tracker.
Skipped when pre_run_count == 0 (cold start — no class mean to compare
against yet). Deletion happens after reconciliation so the Frigate
filename is known. Disabled by default (0.0).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After each successful upload, call POST /api/faces/recognize to get
Frigate's own confidence score (0-1) for the uploaded crop. Store it
in the tracker as frigate_scores alongside the existing blur score.
When quality replacement activates and frigate_scores are present,
use them for the replacement comparison instead of blur scores — an
image Frigate recognizes poorly is a worse training image than one it
recognizes well, regardless of sharpness. Falls back to blur scores
on first run before any frigate_scores are populated.
Also surfaces frigate_score in TRACE_CROP_SIZE output.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Frigate classifies images with Laplacian variance < 120 as "very blurry"
and its own docs recommend avoiding blurry training data. Winnow was
accepting images in the 100-120 range that Frigate considers too blurry.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
50px crops produce ~2,500–4,225 total pixels — well below Frigate's own
camera capture range of 16k–50k px. 90px guarantees ≥8,100 total pixels
even when face margins are fully clipped by image edges.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
50px crops produce ~2,500–4,225 total pixels — well below Frigate's own
camera capture range of 16k–50k px. 90px guarantees ≥8,100 total pixels
even when face margins are fully clipped by image edges.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Store (width, height) of each face crop in the tracker at upload time
alongside the existing blur score. Expose TRACE_CROP_SIZE=<px> to look
up which Immich asset produced a crop with that pixel dimension, making
it straightforward to trace unexpected or low-quality images visible in
Frigate back to their source.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Was >=4.57.6; installed version is 5.12.0. Prevents users from
accidentally resolving the old 4.x series.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
setup-qemu-action v3 → v4, build-push-action v6 → v7
Required before June 16 when Node.js 20 actions are forced to Node.js 24
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- quality.py:122: split long tuple line to satisfy E501 (146 → ≤120)
- update-lockfile.yml: add branches filter so tag pushes don't trigger
the workflow (tag checkout is detached HEAD; git push has no target)
- release.yml: split four Docker build steps into parallel jobs (build-gpu,
build-cpu, build-rocm, build-intel), each with its own runner; previously
all four ran in one job and exhausted disk after GPU+CPU builds, leaving
ROCm and Intel cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
- Pipeline rewritten as 8 steps: separates thumbnail pass (quality filter +
embeddings) from full-res download and crop; adds quality replacement
logic at the upload step
- Persistence note updated to cover rejected IDs and RETRY_REJECTED
- Auto mode stopping threshold documented (20%/10% of median pairwise distance)
- Add OUTPUT_DIR env var (was undocumented)
- Local Install section notes interactive vs auto mode behaviour
- QUALITY_REPLACEMENT description tightened
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- update-lockfile.yml: rename workflow to "Update lockfiles"
- release.yml: add explicit uv python install 3.13 for consistency with other workflows
- docker-publish.yml: rename cpu cache scope from linux/amd64-cpu to cpu (now multi-arch)
- README: add GitHub release version badge and License badge
- README: shorten QUALITY_REPLACEMENT table cell
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- update-lockfile.yml: regenerate all four lockfiles (main + cpu/rocm/intel
variants) on any pyproject change; add variant pyproject files to trigger
- docker-publish.yml: add lockfiles to paths-ignore so the bot commit does
not trigger a second Docker build; remove redundant CONTRIBUTING/SECURITY
entries already covered by **.md; add QEMU to build-cpu; set CPU image to
linux/amd64,linux/arm64 to match release
- release.yml: inline lockfile generation now covers all variants; add
workflow_dispatch guard that fails if not dispatched from main
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dockerfile: ARG VERSION + OCI labels (title, description, source, licenses, version)
- release.yml: pass VERSION build-arg to all four image builds
- docker-publish.yml: extend paths-ignore to cover community files
- .github/ISSUE_TEMPLATE/config.yml: disable blank issues, link to Discussions and wiki
- README.md: add Getting Help section
- pyproject.toml: expand description; add System Administrators audience classifier
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
- Pipeline rewritten as 8 steps: separates thumbnail pass (quality filter +
embeddings) from full-res download and crop; adds quality replacement
logic at the upload step
- Persistence note updated to cover rejected IDs and RETRY_REJECTED
- Auto mode stopping threshold documented (20%/10% of median pairwise distance)
- Add OUTPUT_DIR env var (was undocumented)
- Local Install section notes interactive vs auto mode behaviour
- QUALITY_REPLACEMENT description tightened
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- update-lockfile.yml: rename workflow to "Update lockfiles"
- release.yml: add explicit uv python install 3.13 for consistency with other workflows
- docker-publish.yml: rename cpu cache scope from linux/amd64-cpu to cpu (now multi-arch)
- README: add GitHub release version badge and License badge
- README: shorten QUALITY_REPLACEMENT table cell
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- update-lockfile.yml: regenerate all four lockfiles (main + cpu/rocm/intel
variants) on any pyproject change; add variant pyproject files to trigger
- docker-publish.yml: add lockfiles to paths-ignore so the bot commit does
not trigger a second Docker build; remove redundant CONTRIBUTING/SECURITY
entries already covered by **.md; add QEMU to build-cpu; set CPU image to
linux/amd64,linux/arm64 to match release
- release.yml: inline lockfile generation now covers all variants; add
workflow_dispatch guard that fails if not dispatched from main
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dockerfile: ARG VERSION + OCI labels (title, description, source, licenses, version)
- release.yml: pass VERSION build-arg to all four image builds
- docker-publish.yml: extend paths-ignore to cover community files
- .github/ISSUE_TEMPLATE/config.yml: disable blank issues, link to Discussions and wiki
- README.md: add Getting Help section
- pyproject.toml: expand description; add System Administrators audience classifier
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>