diff --git a/CHANGELOG.md b/CHANGELOG.md index 3329866..afef8c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.5.12] - 2026-06-15 + +### Fixed + +- **Progress task leak on skipped jobs**: `progress.add_task()` is called unconditionally at the top of the job loop, but both early-exit `continue` paths — the `ValueError` skip from `_safe_person_dir` and the symlink-TOCTOU skip added in v0.5.11 — bypassed `progress.remove_task()`, leaving orphaned 0% rows in the terminal display for the rest of the run. Both `continue` paths now call `progress.remove_task(job_task)` before continuing. + ## [0.5.11] - 2026-06-15 ### Fixed diff --git a/pyproject.toml b/pyproject.toml index b7ffd2a..9e6fda2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "winnow" -version = "0.5.11" +version = "0.5.12" description = "Selects diverse, high-quality photos from Immich as training data for Frigate face recognition." license = "AGPL-3.0-or-later" requires-python = ">=3.13" diff --git a/winnow/executor.py b/winnow/executor.py index 6d58aa3..07cabd4 100644 --- a/winnow/executor.py +++ b/winnow/executor.py @@ -105,12 +105,14 @@ def execute_jobs(jobs: list[dict]) -> None: person_dir = _safe_person_dir(Config.OUTPUT_DIR, name) except ValueError as e: logger.error(str(e)) + progress.remove_task(job_task) continue # Face crops are transient (uploaded then discarded); wipe before each run. # A symlink could appear here via a TOCTOU race after _safe_person_dir # returned — writing through it would land crops outside output_dir. if os.path.islink(person_dir): logger.error("person_dir %s became a symlink after path check — skipping job", person_dir) + progress.remove_task(job_task) continue if os.path.isdir(person_dir): shutil.rmtree(person_dir)