1 Commits
Author SHA1 Message Date
Cameron CordesandClaude Opus 5.5 d1f0e4c0c0 feat(insights): read location context from Apollo (#177)
The local location_history table is a one-time Takeout import: it ends
in 2019, still has the ghost-device and coarse cell-fix samples Apollo
has since excluded, and was read loosely. The per-photo line took the
nearest sample within +/-3 h at any distance (17% of photo moments got a
position >2 km away), and get_location_history listed the first 20 rows
of a +/-14-day window sorted ascending (always ~14 days before the date).

With APOLLO_API_BASE_URL set:
- per-photo context comes from /api/location/at (30 min max gap; no
  sample -> no line). A Place stay renders as "at Home (14:02-18:30)" in
  the display zone; an unnamed sample is reverse-geocoded.
- get_location_history returns Apollo's /api/location/day timeline for
  the date (+/-1 day at most), and is offered even with an empty local
  table.

Both fall back to the local table when Apollo is unset or a call fails;
the local tool path now covers the requested local day(s) and samples
evenly instead of listing a window's first rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 23:31:54 -04:00
3 changed files with 8 additions and 102 deletions

No files matched your search

@@ -1,3 +0,0 @@
-- Data fix only: the cleared instants were wrong and are re-resolved by the
-- drain, so there is nothing to restore.
SELECT 1;
@@ -1,17 +0,0 @@
-- #160 follow-up. The first fix (2026-10-16 migration) cleared rows whose
-- legacy `date_taken_source` was 'filename'. But the true-instant drain
-- (#118) re-ran the resolver over rows with a correct legacy date (e.g. an
-- exiftool container date) and wrote only the new-contract triple, so
-- some rows carry a filename-derived implausible year in `date_utc` while
-- their legacy pair says 'exiftool'. On prod: three VID_<counter> videos
-- (years 2095, 2229, 8580) whose containers say 2016/2017.
--
-- Clear just the triple on any row whose true instant is outside
-- [1995-01-01, 2028-01-01) UTC. `date_utc IS NULL` puts it back in
-- `backfill_utc_dates`, which re-resolves it with the gated matcher; the
-- legacy pair is left alone (it's frozen for rollback, and here correct).
UPDATE image_exif
SET date_utc = NULL,
camera_offset_minutes = NULL,
date_taken_tz_source = NULL
WHERE date_utc < 788918400 OR date_utc >= 1830297600;
+8 -82
View File
@@ -495,92 +495,18 @@ mod tests {
assert_eq!(rels, vec!["Screenshot_2014-06-01-20-44-50.png"]);
}
/// A connection migrated up to (not including) the migration whose
/// name contains `name`, for seeding the state a data fix repairs.
fn conn_before_migration(name: &str) -> SqliteConnection {
let mut conn = SqliteConnection::establish(":memory:").expect("in-memory sqlite");
for m in conn.pending_migrations(DB_MIGRATIONS).expect("pending") {
if m.name().to_string().contains(name) {
break;
}
conn.run_migration(&*m).expect("migration");
}
conn
}
#[test]
fn migration_clears_implausible_true_instants_but_keeps_legacy_dates() {
// The prod shape the first fix missed: a correct exiftool legacy
// date, with a filename-derived 2229 instant written by the drain.
let mut conn = conn_before_migration("reresolve_implausible_utc_dates");
seed_row(
&mut conn,
1,
"VID_22290524_080551_818.mp4",
Some(1_500_069_534),
Some("exiftool"),
);
seed_row(&mut conn, 1, "beach.jpg", Some(1_500_069_534), Some("exif"));
let set_utc = |conn: &mut SqliteConnection, path: &str, utc: i64| {
diesel::update(image_exif::table.filter(image_exif::rel_path.eq(path)))
.set((
image_exif::date_utc.eq(utc),
image_exif::camera_offset_minutes.eq(-300),
image_exif::date_taken_tz_source.eq("assumed_server"),
))
.execute(conn)
.unwrap();
};
set_utc(&mut conn, "VID_22290524_080551_818.mp4", 8_185_669_551);
set_utc(&mut conn, "beach.jpg", 1_500_069_534);
conn.run_pending_migrations(DB_MIGRATIONS)
.expect("fix migration");
type Row = (
String,
Option<i64>,
Option<String>,
Option<i64>,
Option<i32>,
);
let rows: Vec<Row> = image_exif::table
.select((
image_exif::rel_path,
image_exif::date_taken,
image_exif::date_taken_source,
image_exif::date_utc,
image_exif::camera_offset_minutes,
))
.order(image_exif::rel_path)
.load(&mut conn)
.unwrap();
assert_eq!(
rows,
vec![
(
"VID_22290524_080551_818.mp4".into(),
Some(1_500_069_534),
Some("exiftool".into()),
None,
None
),
(
"beach.jpg".into(),
Some(1_500_069_534),
Some("exif".into()),
Some(1_500_069_534),
Some(-300)
),
]
);
}
#[test]
fn migration_clears_implausible_filename_dates_for_re_resolution() {
// Migrate up to just before the #160 data fix, seed rows as the
// old matcher left them, then apply it.
let mut conn = conn_before_migration("reresolve_implausible_filename_dates");
const FIX: &str = "reresolve_implausible_filename_dates";
let mut conn = SqliteConnection::establish(":memory:").expect("in-memory sqlite");
for m in conn.pending_migrations(DB_MIGRATIONS).expect("pending") {
if m.name().to_string().contains(FIX) {
break;
}
conn.run_migration(&*m).expect("migration");
}
// 2229-05-24 08:05:51 and 1053-05-19 10:15:27 (wall-as-UTC), a
// real 2014 filename date, and an fs_time row that isn't ours to
// touch even though its date is odd.