fix(backfill): convert exiftool-legacy rows whose only dates are zero #185

Merged
cameron merged 1 commits from fix/utc-backfill-zero-date-exiftool into master 2026-10-17 16:35:12 +00:00
Owner

Problem

Two prod rows (uv-prod-long.mp4, uv-prod-long-v2.mp4) never get date_utc. Legacy source is exiftool, but every date tag in the file is 0000:00:00 00:00:00. The re-resolution lands on fs_time, and backfill_utc_dates refuses fs_time over a tag-sourced legacy date, assuming exiftool failed on the file. It didn't fail. The file has no date, so the rows stay unconverted and go back through exiftool every tick.

Change

  • date_resolver::resolve_dates_batch_report returns BatchResolution { resolved, exiftool_read }. exiftool_read holds the paths exiftool returned an error-free entry for. resolve_dates_batch is now a thin wrapper, so other callers don't change.
  • exiftool now also gets -Error. Under -q, a per-file read error such as File format error or Error opening file otherwise only goes to stderr, and the file's JSON entry looks like a clean read with no tags. Entries with ExifTool:Error don't count as read.
  • backfill_utc_dates: the guard is now utc_resolution_is_faithful. fs_time over a legacy exiftool row is allowed only if exiftool read the file during this pass. It is still refused when:
    • the file has no entry or got a read error (exiftool crashed, partial output, unreadable file)
    • the legacy source is exif (kamadak-exif). A different reader found that date, so exiftool coming up empty doesn't prove the date was bogus.
  • backfill_missing_date_taken doesn't have this gap. It has no such guard and already writes fs_time for date_taken IS NULL rows.

Tests

  • utc_resolution_fs_time_over_tag_date_needs_an_exiftool_read: truth table for the guard (hermetic).
  • parse_payload_flags_read_errors_not_zero_dates: an all-zero payload counts as a clean read with no date, and ExifTool:Error sets the error flag (hermetic).
  • utc_backfill_legacy_exiftool_row_with_only_zero_dates_converts_to_fs_time: an ffmpeg mp4 with zeroed QuickTime/Track dates converts to its fs time (utc_direct) and the legacy pair stays frozen. A binary-junk file with an exiftool File format error stays unresolved (needs ffmpeg + exiftool).
  • Full suite: 871 lib tests pass. Clippy --all-targets is clean.

🤖 Generated with Claude Code

## Problem Two prod rows (`uv-prod-long.mp4`, `uv-prod-long-v2.mp4`) never get `date_utc`. Legacy source is `exiftool`, but every date tag in the file is `0000:00:00 00:00:00`. The re-resolution lands on `fs_time`, and `backfill_utc_dates` refuses fs_time over a tag-sourced legacy date, assuming exiftool failed on the file. It didn't fail. The file has no date, so the rows stay unconverted and go back through exiftool every tick. ## Change - `date_resolver::resolve_dates_batch_report` returns `BatchResolution { resolved, exiftool_read }`. `exiftool_read` holds the paths exiftool returned an error-free entry for. `resolve_dates_batch` is now a thin wrapper, so other callers don't change. - exiftool now also gets `-Error`. Under `-q`, a per-file read error such as `File format error` or `Error opening file` otherwise only goes to stderr, and the file's JSON entry looks like a clean read with no tags. Entries with `ExifTool:Error` don't count as read. - `backfill_utc_dates`: the guard is now `utc_resolution_is_faithful`. fs_time over a legacy `exiftool` row is allowed only if exiftool read the file during this pass. It is still refused when: - the file has no entry or got a read error (exiftool crashed, partial output, unreadable file) - the legacy source is `exif` (kamadak-exif). A different reader found that date, so exiftool coming up empty doesn't prove the date was bogus. - `backfill_missing_date_taken` doesn't have this gap. It has no such guard and already writes fs_time for `date_taken IS NULL` rows. ## Tests - `utc_resolution_fs_time_over_tag_date_needs_an_exiftool_read`: truth table for the guard (hermetic). - `parse_payload_flags_read_errors_not_zero_dates`: an all-zero payload counts as a clean read with no date, and `ExifTool:Error` sets the error flag (hermetic). - `utc_backfill_legacy_exiftool_row_with_only_zero_dates_converts_to_fs_time`: an ffmpeg mp4 with zeroed QuickTime/Track dates converts to its fs time (`utc_direct`) and the legacy pair stays frozen. A binary-junk file with an exiftool `File format error` stays unresolved (needs ffmpeg + exiftool). - Full suite: 871 lib tests pass. Clippy `--all-targets` is clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
cameron added 1 commit 2026-10-17 16:17:32 +00:00
backfill_utc_dates refused any fs_time re-resolution of a tag-dated row,
assuming exiftool had failed on the file. Files whose date tags are all
0000:00:00 (e.g. uv-prod-long.mp4) were read fine and simply have no
date, so they sat unconverted and re-ran through exiftool every tick.

resolve_dates_batch_report now also returns the paths exiftool read
without error (-Error surfaces ExifTool:Error in the JSON). The drain
lets fs_time stand for an exiftool-legacy row only when exiftool read
the file; read errors / missing entries and kamadak exif-legacy rows
keep refusing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cameron merged commit fdbcc75391 into master 2026-10-17 16:35:12 +00:00
cameron deleted branch fix/utc-backfill-zero-date-exiftool 2026-10-17 16:35:12 +00:00
Sign in to join this conversation.