fix(versions): review findings on PR #193

- A version no longer hides behind an original that duplicates resolve
  demoted (visible_version_clause, hidden_version_rows).
- Recording a link drops the version's faces, CLIP data and clip failures
  (covers link-at-ingest and link_versions --apply).
- The display file must live in the original's library; otherwise the
  original shows, and PUT /image/versions/display answers 400.
- link_new_files looks up hashes in chunks of 500 and logs errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cameron CordesandClaude Opus 5.5 committed 2026-10-30 14:27:54 -04:00
1 parent 6135034d09
commit 9f50843479
6 files changed
+402 -47

No files matched your search

+48
View File
@@ -928,4 +928,52 @@ mod tests {
let report = apply(&mut dao, &[], &reviewed, &stale_rows);
assert_eq!(report.stale, 1);
}
#[test]
fn apply_drops_derived_data_of_an_already_ingested_version() {
let conn = Arc::new(Mutex::new(in_memory_db_connection()));
let exec = |sql: &str| {
diesel::RunQueryDsl::execute(diesel::sql_query(sql), &mut *conn.lock().unwrap())
.unwrap_or_else(|e| panic!("{sql}: {e}"));
};
exec(
"INSERT INTO image_exif (library_id, rel_path, created_time, last_modified, content_hash, clip_embedding, clip_model_version) VALUES (1, 'v.png', 0, 0, 'v', x'00', 'm')",
);
exec(
"INSERT INTO face_detections (library_id, content_hash, rel_path, bbox_x, embedding, source, status, model_version, created_at) VALUES (1, 'v', 'v.png', 0.1, x'00', 'auto', 'detected', 'm', 0)",
);
exec(
"INSERT INTO clip_failures (library_id, rel_path, content_hash, error, failed_at) VALUES (1, 'v.png', 'v', 'boom', 0)",
);
let mut dao = SqliteVersionDao::from_shared(conn.clone());
let rows = vec![row("v.png", "v", None)];
let reviewed = vec![ReviewedLink {
method: "phash".into(),
library_id: 1,
version_path: "v.png".into(),
kind: "edit".into(),
version_hash: "v".into(),
original_hash: "o".into(),
references: vec![],
}];
assert_eq!(apply(&mut dao, &[], &reviewed, &rows).linked, 1);
#[derive(diesel::QueryableByName)]
struct N {
#[diesel(sql_type = diesel::sql_types::BigInt)]
n: i64,
}
for sql in [
"SELECT COUNT(*) AS n FROM face_detections WHERE content_hash = 'v'",
"SELECT COUNT(*) AS n FROM clip_failures WHERE content_hash = 'v'",
"SELECT COUNT(*) AS n FROM image_exif WHERE content_hash = 'v' AND (clip_embedding IS NOT NULL OR clip_model_version IS NOT NULL)",
] {
let n = diesel::RunQueryDsl::get_result::<N>(
diesel::sql_query(sql),
&mut *conn.lock().unwrap(),
)
.unwrap()
.n;
assert_eq!(n, 0, "{sql}");
}
}
}