feat(versions): link at ingest, hide in listings, version endpoints

XMP (PNG iTXt DerivedFrom, native chunk reader) then file-name convention
links at ingest; unlinked name candidates are retried each tick. Versions
are hidden from /photos (SQL for the recursive listing, hidden-row set for
the walk and tag branches), /memories, reels, /photos/exif, the GPS summary,
unified search and the media gauges while their original is reachable in the
view; include_versions=true lists them. /photos gains the parallel arrays
photo_display_paths / photo_version_counts, memories / search hits /
/photos/exif rows gain display_path / version_count, all skipped when empty.
GET /image/versions and PUT /image/versions/display (library optional).
Tags and favorites on a version path bind to the original; faces, CLIP and
duplicate grouping skip version hashes; insight generation redirects to the
original. Orphan GC and the back-ref refresh cover the new tables.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cameron CordesandClaude Opus 5.5 committed 2026-10-30 11:28:34 -04:00
1 parent 044240037a
commit 080a75c336
24 files changed
+1614 -47

No files matched your search

+20
View File
@@ -430,7 +430,17 @@ pub async fn generate_insight_handler(
&mut request.persona_id,
);
// Insights describe the original: asking for one on a photo version
// (#191) runs against the original it belongs to.
let normalized_path = normalize_path(&request.file_path);
let normalized_path = app_state
.version_dao
.lock()
.expect("Unable to lock VersionDao")
.original_path_of(&normalized_path)
.ok()
.flatten()
.unwrap_or(normalized_path);
let library = app_state.primary_library();
let gen_type = InsightGenerationType::Standard;
@@ -748,7 +758,17 @@ pub async fn generate_agentic_insight_handler(
&mut request.persona_id,
);
// Insights describe the original: asking for one on a photo version
// (#191) runs against the original it belongs to.
let normalized_path = normalize_path(&request.file_path);
let normalized_path = app_state
.version_dao
.lock()
.expect("Unable to lock VersionDao")
.original_path_of(&normalized_path)
.ok()
.flatten()
.unwrap_or(normalized_path);
let library = app_state.primary_library();
let gen_type = InsightGenerationType::Agentic;
+1 -1
View File
@@ -2544,7 +2544,7 @@ Return ONLY the summary, nothing else."#,
);
let rows = {
let mut dao = self.exif_dao.lock().expect("Unable to lock ExifDao");
match dao.query_by_exif(None, None, None, None, None, range) {
match dao.query_by_exif(None, None, None, None, None, range, false) {
Ok(r) => r,
Err(e) => return format!("Error querying photos: {:?}", e),
}