Skip to content

feat(photo-exif): suggest cluster labels from single-name Google Photos sidecars#274

Merged
MSIH merged 2 commits into
mainfrom
feat/272-suggest-sidecars
Jul 25, 2026
Merged

feat(photo-exif): suggest cluster labels from single-name Google Photos sidecars#274
MSIH merged 2 commits into
mainfrom
feat/272-suggest-sidecars

Conversation

@MSIH

@MSIH MSIH commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Closes #272

Summary

  • Adds node face-worker.js suggest-from-sidecars: joins the face scan's own state (a photo with exactly one detected face in exactly one cluster) against Google Photos sidecar people[] tags to vote a majority name per unlabeled cluster.
  • No ONNX/detection call, no contact photos, no network — reads persisted FACE_STATE + sidecars only. Suggest-only: never writes cluster.label, never emits an ingest hint, never mutates the clusters/face-state files.
  • A suggestion requires the top name to clear both FACE_SEED_MIN_VOTES (default 3) and FACE_SEED_MIN_FRACTION (default 0.7) so a stray mis-tag or an impure/merged cluster doesn't produce a confident wrong label.
  • Downstream of feat(photo-exif): swap face stack from tfjs-node to onnxruntime-node #268 (ONNX face detection) and chore(photo-exif): tag people in the photo library (face pass) #217 (backfill run) — those populate the face clusters/state this command reads.

Changes

  • connectors/photo-exif/face-worker.js — new suggestFromSidecars() + suggest-from-sidecars dispatch + FACE_SEED_MIN_VOTES/FACE_SEED_MIN_FRACTION env thresholds
  • connectors/photo-exif/.env.example — documents the new subcommand + thresholds
  • connectors/photo-exif/README.md — new suggest-from-sidecars section
  • connectors/photo-exif/test.mjs — 5 new tests: clear-majority suggestion, split vote below threshold, already-labeled cluster excluded, mutates/posts nothing, PHOTO_ROOT missing → exit 1, no votes → clean exit 0, all-labeled early exit

Verification

  • npm test — 27/28 passing; the 1 failure is the same pre-existing Windows/Node-v26 test-runner crash noted in feat(photo-exif): swap face stack from tfjs-node to onnxruntime-node #273, reproduces identically on main, confirmed green on real CI (Ubuntu/Windows × Node 20/22)
  • npm run check:boundary — clean
  • Solo multi-persona review (equivalent to /pre-pr-review's automated step, since direct skill invocation isn't available in this session) found no issues — this is a small, pure, network-free addition

Test plan

  • npm test passes (aside from the pre-existing unrelated flake noted above)
  • npm run check:boundary passes
  • Manually: after a real scan + face pass over a Takeout library, run node face-worker.js suggest-from-sidecars and confirm suggestions look reasonable before confirming with label <id> "<name>"

…os sidecars (#272)

Adds `node face-worker.js suggest-from-sidecars`: joins the face scan's own state (single-face, single-cluster photos) against Google Photos sidecar people[] tags to vote a majority name per unlabeled cluster, gated on FACE_SEED_MIN_VOTES/FACE_SEED_MIN_FRACTION. Suggest-only — never writes a label, never touches the network, needs zero ONNX/detection.
Copilot AI review requested due to automatic review settings July 25, 2026 08:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new photo-exif face-worker subcommand that suggests names for unlabeled face clusters by voting Google Photos Takeout sidecar people[] tags against the persisted face scan state—without running detection, doing network calls, or mutating cluster/state files.

Changes:

  • Add node face-worker.js suggest-from-sidecars to compute per-cluster majority-name suggestions from single-face / single-name sidecar votes, gated by new env thresholds.
  • Document the new command and thresholds in the connector README and .env.example.
  • Add fixture-driven tests covering suggestion behavior, early exits, and “no writes / no posts” guarantees.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
connectors/photo-exif/face-worker.js Adds suggestFromSidecars() implementation, CLI dispatch, and env-configured vote thresholds.
connectors/photo-exif/test.mjs Adds tests for sidecar-vote-based suggestions, early-exit behavior, and edge cases.
connectors/photo-exif/README.md Documents the new suggest-from-sidecars subcommand and its thresholding/safety posture.
connectors/photo-exif/.env.example Documents FACE_SEED_MIN_VOTES / FACE_SEED_MIN_FRACTION and the new subcommand usage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread connectors/photo-exif/face-worker.js Outdated
Comment on lines +62 to +65
const minVotesRaw = Number(process.env.FACE_SEED_MIN_VOTES);
const FACE_SEED_MIN_VOTES = Number.isFinite(minVotesRaw) ? minVotesRaw : 3;
const minFractionRaw = Number(process.env.FACE_SEED_MIN_FRACTION);
const FACE_SEED_MIN_FRACTION = Number.isFinite(minFractionRaw) ? minFractionRaw : 0.7;
…-of-range

Copilot review on #274 caught that Number('')+isFinite parses a blank env value as 0, which would silently disable the suggest-from-sidecars confidence gate (any single vote would then qualify). Requires both values to be a positive number, and the fraction additionally <=1.
@MSIH

MSIH commented Jul 25, 2026

Copy link
Copy Markdown
Owner Author

Resolving Copilot's review (1 comment):

  • Accepted — `face-worker.js:65`: `Number()`+`Number.isFinite` parses a blank `FACE_SEED_MIN_VOTES=`/`FACE_SEED_MIN_FRACTION=` as `0` (finite), which would silently disable the confidence gate this feature exists to provide — any single vote would then qualify. Fixed in dfc80b4: both now require a positive value, and the fraction additionally `<=1`. Added a regression test asserting a blank env doesn't auto-suggest a single-vote cluster.

@MSIH
MSIH merged commit a9ed261 into main Jul 25, 2026
5 checks passed
@MSIH
MSIH deleted the feat/272-suggest-sidecars branch July 25, 2026 08:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(photo-exif): suggest cluster labels from single-name Google Photos sidecars

3 participants