Implements the full M1 plan (docs/superpowers/plans/2026-06-27-immich-photo-flow-m1.md): the photoflow shared monorepo and the trip-cluster Flask app end-to-end — ingest -> density-adaptive clustering -> review UI -> idempotent write-back to Immich.
shared/photoflow/immich — the one Immich REST client + _pipeline/ tag conventions
shared/photoflow/core — SQLite store + domain models (the only SQL owner)
shared/photoflow/ui — base template, DaisyUI/Tailwind/Alpine/HTMX, shared grid+lightbox
apps/trip-cluster — argparse CLI (ingest|cluster|serve|apply) + master/detail review UI on port 8084
All 17 plan tasks shipped, built TDD (failing test first per unit). Immich is the source of truth; SQLite is a rebuildable working layer; write-back is idempotent (writeback_log) and confirmation-gated.
Tests
66 green: 60 unit/route (pytest + pytest-httpserver, Immich mocked) + 6 Playwright UI. Dev env runs Python 3.14; the Docker/target runtime stays 3.12; all pinned deps install on both.
Review
A 6-reviewer pass (correctness, security, reliability, maintainability, testing, project-standards) ran on the branch. No exploitable security issues. Nine findings fixed with regression tests:
P1 — upsert_tag failure no longer aborts the whole apply_all batch (moved inside the per-asset try/except)
P2 — processed-tag write failures surfaced in the result; confirmation gate on single-cluster apply; approve-high-confidence count fixed; DB connection closed even if a route raises; incremental-ingest watermark no longer strands thumbnail-failed assets
## What
Implements the full **M1** plan (`docs/superpowers/plans/2026-06-27-immich-photo-flow-m1.md`): the `photoflow` shared monorepo and the `trip-cluster` Flask app end-to-end — ingest -> density-adaptive clustering -> review UI -> idempotent write-back to Immich.
- `shared/photoflow/immich` — the one Immich REST client + `_pipeline/` tag conventions
- `shared/photoflow/core` — SQLite store + domain models (the only SQL owner)
- `shared/photoflow/ui` — base template, DaisyUI/Tailwind/Alpine/HTMX, shared grid+lightbox
- `apps/trip-cluster` — argparse CLI (`ingest|cluster|serve|apply`) + master/detail review UI on port 8084
All 17 plan tasks shipped, built TDD (failing test first per unit). Immich is the source of truth; SQLite is a rebuildable working layer; write-back is idempotent (`writeback_log`) and confirmation-gated.
## Tests
66 green: 60 unit/route (pytest + pytest-httpserver, Immich mocked) + 6 Playwright UI. Dev env runs Python 3.14; the Docker/target runtime stays 3.12; all pinned deps install on both.
## Review
A 6-reviewer pass (correctness, security, reliability, maintainability, testing, project-standards) ran on the branch. No exploitable security issues. Nine findings fixed with regression tests:
- **P1** — `upsert_tag` failure no longer aborts the whole `apply_all` batch (moved inside the per-asset try/except)
- **P2** — processed-tag write failures surfaced in the result; confirmation gate on single-cluster apply; `approve-high-confidence` count fixed; DB connection closed even if a route raises; incremental-ingest watermark no longer strands thumbnail-failed assets
- **P3** — `split_cluster` empty-cluster guard; `writeback_log` index; ingest `.tmp` cleanup
Remaining items are report-only cleanups and do not block merge.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- write-back: call upsert_tag inside _apply_tag's try so a tag-create failure
is caught per-asset and apply_all no longer aborts mid-batch (was P1)
- write-back: surface _pipeline/processed write failures in the result instead
of discarding them (was reported as success)
- ui: add title to the high confidence badge so approve-high-confidence's
pre-action count is non-zero; confirm() before single-cluster apply
- core: Store context manager; close DB connection even if a route raises;
guard split_cluster against a first-member boundary (empty cluster); add
writeback_log lookup index
- ingest: split thumbnail download/write error handling and clean up the
.tmp file on a write failure
- tests: upsert/processed write-failure regression tests + split-guard test
A later successful asset could push last_ingest_at past an earlier asset whose
thumbnail download failed, permanently excluding it from later incremental runs
(only --full recovered it). Now the cursor never advances to/past the earliest
failed asset, never below the prior cursor, and not at all on a --subset run.
Regression tests added. (review finding #9)
m038
merged commit d5b073da9c into master2026-06-27 19:10:50 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
Implements the full M1 plan (
docs/superpowers/plans/2026-06-27-immich-photo-flow-m1.md): thephotoflowshared monorepo and thetrip-clusterFlask app end-to-end — ingest -> density-adaptive clustering -> review UI -> idempotent write-back to Immich.shared/photoflow/immich— the one Immich REST client +_pipeline/tag conventionsshared/photoflow/core— SQLite store + domain models (the only SQL owner)shared/photoflow/ui— base template, DaisyUI/Tailwind/Alpine/HTMX, shared grid+lightboxapps/trip-cluster— argparse CLI (ingest|cluster|serve|apply) + master/detail review UI on port 8084All 17 plan tasks shipped, built TDD (failing test first per unit). Immich is the source of truth; SQLite is a rebuildable working layer; write-back is idempotent (
writeback_log) and confirmation-gated.Tests
66 green: 60 unit/route (pytest + pytest-httpserver, Immich mocked) + 6 Playwright UI. Dev env runs Python 3.14; the Docker/target runtime stays 3.12; all pinned deps install on both.
Review
A 6-reviewer pass (correctness, security, reliability, maintainability, testing, project-standards) ran on the branch. No exploitable security issues. Nine findings fixed with regression tests:
upsert_tagfailure no longer aborts the wholeapply_allbatch (moved inside the per-asset try/except)approve-high-confidencecount fixed; DB connection closed even if a route raises; incremental-ingest watermark no longer strands thumbnail-failed assetssplit_clusterempty-cluster guard;writeback_logindex; ingest.tmpcleanupRemaining items are report-only cleanups and do not block merge.
🤖 Generated with Claude Code