Commit Graph
218 Commits
Author SHA1 Message Date
flanandClaude Sonnet 4.6 4856a6d36f fix: raise MIN_FACE_WIDTH default from 50 to 90px (8k pixel floor)
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>
2026-06-13 15:45:12 +00:00
github-actions[bot] c0c2d88941 chore: update lockfiles 2026-06-13 15:33:25 +00:00
flanandClaude Sonnet 4.6 82dbc8502a feat: merge crop-dimension-trace into dev
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 15:32:27 +00:00
flanandClaude Sonnet 4.6 6311227763 chore: regenerate uv.lock for 0.3.2 version bump
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 15:30:14 +00:00
flanandClaude Sonnet 4.6 19416cc7b8 feat: record crop pixel dimensions and add TRACE_CROP_SIZE lookup
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>
2026-06-13 15:20:54 +00:00
flanandClaude Sonnet 4.6 80c5b563b2 Merge main: bump transformers lower bound to >=5.12.0 in variant files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:54:02 +00:00
flanandClaude Sonnet 4.6 de1df19642 chore: bump transformers lower bound to >=5.12.0 in variant pyproject files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:53:56 +00:00
github-actions[bot] 3ae6a86684 chore: update lockfiles 2026-06-13 14:53:14 +00:00
github-actions[bot] 621c310d5b chore: update lockfiles 2026-06-13 14:52:59 +00:00
flanandClaude Sonnet 4.6 467f258fa5 chore: bump transformers lower bound to >=5.12.0
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>
2026-06-13 14:52:27 +00:00
flanandClaude Sonnet 4.6 36a5fb56b6 fix: revert ruff-action to v3 (v4 major tag does not exist)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:47:31 +00:00
flanandClaude Sonnet 4.6 f90af65cd2 fix: revert setup-uv to v7 (v8 major tag does not exist)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:45:02 +00:00
flanandClaude Sonnet 4.6 cd3fad8afe chore: bump astral-sh actions to latest major versions
ruff-action v3 → v4, setup-uv v7 → v8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:42:43 +00:00
flanandClaude Sonnet 4.6 102827537e Merge dev: bump docker actions to Node.js 24-compatible versions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:40:48 +00:00
flanandClaude Sonnet 4.6 aa12c79f9d chore: bump docker actions to Node.js 24-compatible versions
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>
2026-06-13 14:40:37 +00:00
github-actions[bot] 0f6b17f76f chore: update lockfiles 2026-06-13 14:26:04 +00:00
github-actions[bot] c61e4dc698 chore: update lockfiles 2026-06-13 14:26:03 +00:00
flanandClaude Sonnet 4.6 18f3171667 Bump version to 0.3.1 and update CHANGELOG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.3.1
2026-06-13 14:25:30 +00:00
flanandClaude Sonnet 4.6 1fdb35727e Merge dev: fix CI lint, lockfile workflow, release disk exhaustion
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:24:51 +00:00
flanandClaude Sonnet 4.6 870560de1a Fix CI: lint line-length, lockfile detached HEAD, release disk exhaustion
- 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>
2026-06-13 14:23:33 +00:00
github-actions[bot] b29b98fa29 chore: update lockfiles 2026-06-13 06:53:48 +00:00
github-actions[bot] 40c2a850bc chore: update lockfiles 2026-06-13 06:53:22 +00:00
flanandClaude Sonnet 4.6 3e8dddb050 Bump version to 0.3.0 and update CHANGELOG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.3.0
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 12789e83f2 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>
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 8ee370406b Update README to reflect current pipeline and features
- 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>
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 5ab2cf2ac5 Polish build flow and README formatting
- 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>
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 608ade8499 Fix build flow: lockfile bot, CPU multi-arch, paths-ignore, release guard
- 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>
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 7e90b8e669 Add OCI image labels, issue template config, paths-ignore, and metadata fixes
- 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>
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 694e9af127 Add community scaffolding: CONTRIBUTING, SECURITY, issue templates, PR template
- CONTRIBUTING.md: dev-branch workflow, uv setup, test/lint commands
- SECURITY.md: private disclosure to holden@arch.fyi
- .github/ISSUE_TEMPLATE/bug_report.yml: structured form with image tag, versions, logs
- .github/ISSUE_TEMPLATE/feature_request.yml: problem/solution/alternatives form
- .github/PULL_REQUEST_TEMPLATE.md: checklist enforcing dev branch + passing CI
- pyproject.toml: add Changelog and Documentation URLs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 06:52:51 +00:00
flanandClaude Sonnet 4.6 2cee73fd6f Bump version to 0.3.0 and update CHANGELOG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 06:52:38 +00:00
flanandClaude Sonnet 4.6 3da5f67c21 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>
2026-06-13 06:52:38 +00:00
flanandClaude Sonnet 4.6 ac249e6242 Update README to reflect current pipeline and features
- 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>
2026-06-13 06:52:38 +00:00
flanandClaude Sonnet 4.6 0e2915f564 Polish build flow and README formatting
- 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>
2026-06-13 06:52:38 +00:00
flanandClaude Sonnet 4.6 cf760df930 Fix build flow: lockfile bot, CPU multi-arch, paths-ignore, release guard
- 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>
2026-06-13 06:52:38 +00:00
flanandClaude Sonnet 4.6 7613fdcd5b Add OCI image labels, issue template config, paths-ignore, and metadata fixes
- 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>
2026-06-13 06:52:38 +00:00
flanandClaude Sonnet 4.6 b786199a4f Add community scaffolding: CONTRIBUTING, SECURITY, issue templates, PR template
- CONTRIBUTING.md: dev-branch workflow, uv setup, test/lint commands
- SECURITY.md: private disclosure to holden@arch.fyi
- .github/ISSUE_TEMPLATE/bug_report.yml: structured form with image tag, versions, logs
- .github/ISSUE_TEMPLATE/feature_request.yml: problem/solution/alternatives form
- .github/PULL_REQUEST_TEMPLATE.md: checklist enforcing dev branch + passing CI
- pyproject.toml: add Changelog and Documentation URLs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 06:52:38 +00:00
github-actions[bot] 2055fe7aae chore: update uv.lock 2026-06-13 05:56:49 +00:00
github-actions[bot] fd65157c25 chore: update uv.lock 2026-06-13 05:56:22 +00:00
flanandClaude Sonnet 4.6 d2bc7a94b1 Merge dev into main: NOTICES + 0.2.13
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:55:59 +00:00
flanandClaude Sonnet 4.6 0ce67a7570 Add NOTICES file for if_curator MIT attribution; bump to 0.2.13
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:55:51 +00:00
flanandClaude Sonnet 4.6 650dadd102 Cap quality replacement against tracked files only, not total Frigate count
Previously, effective_count and the jobs.py cap check used the total
Frigate file count (including manually-added files), so any file a user
curated by hand ate into winnow's managed quota. Now:

- get_tracked_frigate_file_count() returns len(frigate_files) from the
  tracker — only files winnow uploaded and reconciled
- effective_count in the upload loop uses this tracker count so
  manually-added files are invisible to the cap
- jobs.py capacity check uses len(frigate_files) instead of the live
  Frigate API count or cached frigate_count
- Frigate API call for known_frigate_files_at_start is now only used
  for the post-upload reconciliation diff, not for cap enforcement

Side-effect: fixes audit bug #1 — an unreachable Frigate GET no longer
zeroes effective_count and bypasses the cap, because the cap is now
read from the always-available local tracker.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:35:26 +00:00
flanandClaude Sonnet 4.6 1615e2e77e Merge feature/quality-replacement into dev
Adds quality replacement for Frigate face training images:
- When a person is at MAX_AUTO_IMAGES cap, replace the lowest-quality
  mapped Frigate file if a better candidate is available
- Quality score is laplacian blur variance from the quality filtering
  pipeline (stored on asset, propagated through tracker)
- Frigate filename mapping uses post-person batch reconciliation:
  poll after all uploads complete, map by filename timestamp order
  (documented race condition limitation in code)
- QUALITY_REPLACEMENT env var (default true) to disable the feature
- Bug fix: f-string TypeError when no mapped files exist (worst=None)
- CI: more aggressive runner disk cleanup to fix NVIDIA build OOM

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:18:26 +00:00
flanandClaude Sonnet 4.6 785ac3cbc6 Add QUALITY_REPLACEMENT to config tests; expand CI disk cleanup
Config tests now verify QUALITY_REPLACEMENT defaults to True and
respects the QUALITY_REPLACEMENT=false env override.

CI: replace minimal disk cleanup with more aggressive removal
(Android SDK ~14GB, Swift, CodeQL, docker system prune) so the
NVIDIA GPU image build no longer exhausts runner disk space.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:18:15 +00:00
flanandClaude Sonnet 4.6 12bccaa631 Fix TypeError when worst mapped file is None in quality replacement
When no mapped files exist for a person, worst is None and the old
f-string tried to subscript it before the conditional was evaluated.
Extracted worst_score_str as a local variable to avoid the crash.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:14:15 +00:00
flanandClaude Sonnet 4.6 11e7d4aad7 Implement quality score tracking and batch Frigate file mapping
- Track laplacian blur score through quality filtering pipeline
  (quality.py: blur_score on QualityResult; diversity.py: store on asset;
   executor.py: read via quality_score key)
- Replace per-file polling with post-person batch reconciliation:
  after all uploads for a person complete, poll Frigate (up to 15s)
  until the expected number of new files appear, then map by filename
  timestamp order (Frigate FIFO queue = upload order = timestamp order)
- Document race condition limitation: concurrent external uploads cause
  the batch to be skipped entirely (safe but files go unmapped); noted
  in code as requiring a Frigate API fix (return filename on upload)
- Add two assess_quality integration tests for blur_score

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 04:59:12 +00:00
flanandClaude Sonnet 4.6 4c8c219598 Fix Intel GPU Docker build: libze-intel-gpu1 renamed to level-zero
Intel renamed libze-intel-gpu1 to level-zero in their graphics repository,
breaking the amd64 Intel GPU image build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 04:09:18 +00:00
flanandClaude Sonnet 4.6 9f92e1c919 Fix Intel GPU Docker build: libze-intel-gpu1 renamed to level-zero
Intel renamed libze-intel-gpu1 to level-zero in their graphics repository,
breaking the amd64 Intel GPU image build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 04:08:22 +00:00
flanandClaude Sonnet 4.6 615c3c3cc6 Fix ruff import ordering in executor.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 03:53:28 +00:00
flanandClaude Sonnet 4.6 a0083cb9fe Fix three bugs found by code audit
- Delete failure retry loop: when delete_frigate_person_files() fails,
  remove the file from the tracker so the next candidate targets a
  different worst file rather than re-attempting the same failed delete.

- Interactive mode quality replacement: _configure_person() never set
  config["quality_replacement"], causing the executor to always default
  to False and silently skip all uploads for at-cap interactive jobs.
  Now mirrors auto_configure by reading Config.QUALITY_REPLACEMENT.

- Silent mapping loss on API flap: after a successful upload, if the
  post-upload GET /api/faces returns None (transient API failure),
  the file was silently left unmapped. Now logs a warning so users
  know quality replacement won't target that file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 03:52:04 +00:00
flanandClaude Sonnet 4.6 129c74720e Add quality replacement for Frigate face training images
When a person is at MAX_AUTO_IMAGES, winnow now replaces the
lowest-quality mapped training image in Frigate if a higher-confidence
candidate is available, keeping the training set always optimised.

Only files winnow uploaded (tracked via frigate_files mapping) are ever
replaced — manually added Frigate training images are never touched.
A concurrent-upload race condition is detected per-file: if N>1 new
files appear after one upload, the mapping is skipped rather than
guessed, logging at INFO level. The per-file snapshot approach is
retained over a batch approach because wrong mappings (which a batch
approach risks on race) are worse than no mapping.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 03:44:36 +00:00