feat: M1 foundation packages + trip-cluster app #1

Merged
m038 merged 19 commits from feat/m1-foundation-trip-cluster into master 2026-06-27 19:10:50 +02:00
Owner

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:

  • P1upsert_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
  • P3split_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

## 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)
m038 added 19 commits 2026-06-27 19:07:31 +02:00
- 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 master 2026-06-27 19:10:50 +02:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m038/immich-photo-flow#1