Import photo location history during onboarding - #201
Open
kyleve wants to merge 7 commits into
Open
Conversation
kyleve
commented
Aug 8, 2026
| let capturedAt = asset.capturedAt, | ||
| let addedAt = asset.addedAt, | ||
| interval.contains(capturedAt), | ||
| abs(addedAt.timeIntervalSince(capturedAt)) <= Self.captureAddedTolerance, |
Owner
Author
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Review focus: PhotoKit does not expose capture-device identity. This five-minute capture-to-library-added tolerance is the best-effort proxy selected for this flow; it deliberately excludes obvious later saves but cannot rule out immediately shared or synchronized photos.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.photoprovenance, use deterministic identifiers for repeat-import deduplication, and audit user correctionsWhy
A first install otherwise starts the year empty even when the user's own photo library contains enough location metadata to reconstruct useful travel history. The import remains optional and provisional so Photos permission, origin filtering, and inferred stays are visible choices rather than background behavior.
Product behavior
After choosing and styling regions, onboarding offers to scan photo locations. The user can skip without writing anything, or grant Photos access and review the inferred stays. Date ranges can be corrected, excluded, and restored before approval.
Approving the draft does not create services early. It carries the draft to main's final per-device recording-choice page; final confirmation opens the real scope, commits and reconciles the selected regions, persists the photo transaction in the current data generation, configures recording, and completes onboarding. If region or photo persistence fails, the flow returns to the editable preview with an honest error state.
Privacy and origin filtering
The PhotoKit adapter reads only capture date, library-added date, coordinate, accuracy, source bucket, and hidden state.
PhotoKit does not expose the originating device identity. The implementation therefore applies a conservative “likely taken on this device” policy: main user library, image assets only, not hidden, valid location metadata, and capture time within five minutes of the library-added time. Shared-album and synced-library sources are excluded.
Architecture
PhotoHistoryPlannercreates an in-memory draft from the metadata-onlyPhotoLocationLibraryseam.OnboardingFlowModelowns scan/review state and retains an approved draft until final confirmation;OnboardingViewonly renders and routes.DayJournal.importPhotoHistory(_:)commits deterministic.photosamples and audited authoritative corrections in one current-generation transaction, then runs the ordinary day-data fan-out.WhereServices.setPrimaryRegions(_:)waits for the serialized live attributor reconciliation before a dependent import can publish widgets or reminders.SampleSource.photovocabulary; the out-of-band upgrader carries v1–v4 archives forward without inventing photo records.Design decisions
The five-minute capture/added-date heuristic favors false negatives over importing shared or synchronized photos. It cannot prove device origin because PhotoKit exposes no stable originating-device identifier.
The import waits for final recording confirmation rather than opening the service scope when the user approves the preview. This preserves main's onboarding invariant that device discovery may prepare the store, but services, App Intents, and GPS remain dormant until the user finishes choosing a world.
Backup format v5 is intentionally rejected by older readers. Archives containing
.photocannot be safely decoded by a build whose sample-source vocabulary predates this feature.Compatibility
Existing v1–v4 archives can be reshaped to v5 with
Where/Tools/upgrade-backup.rb; their existing source values require no photo-specific transformation. Photo samples remain device-agnostic user-approved data, so device-removal filtering preserves them.Review focus
OnboardingFlowModel.finish(using:)Backlog reconciliation
The completed photo-import item moved to
Where/TODOs.md's completed section. Main's new onboarding follow-ups remain open.Testing
./swiftformat --lint— 0 files require formatting./xcstrings --lint— 7 catalogs match Xcode serializationmise exec -- ruby Where/Tools/Tests/upgrade_backup_test.rb— 7 runs, 17 assertions passed./test --no-generate WhereCoreTests— 557 tests passed./test --no-generate WhereUITests— 425 tests passed./test --no-generate --all— 1,843 tests passed./test --no-generate --snapshots— every non-photo snapshot suite passed; the photo accessibility references changed under main's intrinsic-height capture behavior./test --no-generate --snapshots --only 'WhereUISnapshotTests/OnboardingPhotoImportViewSnapshotTests'— passed after visual review and reference refreshswift run bumper config .swift run bumper test .swift run bumper lint . --timings