feat(dates): filename date class — per-pattern conventions + filename-over-EXIF priority (#116)
The filename date class is now first-class (ADR-0001): - memories::extract_date_from_filename returns FilenameDate: Wall(NaiveDateTime) for the screenshot/dash/compact patterns, Utc(DateTime<Utc>) for the unix-timestamp patterns. No patterns added or removed; every existing pattern carries its convention. - Waterfall inversion in both resolve_date_taken and resolve_dates_batch: an in-class name is the original date of record and resolves BEFORE EXIF / container dates are consulted (shared filename_class_resolved step; in-class files skip exiftool entirely). Wall patterns run the offset cascade over the kamadak prior's evidence (empty evidence -> server-zone assumption, so a class file always resolves); timestamp patterns are true instants (tz_source utc_direct, no offset). - Legacy date_taken stays byte-identical: wall-as-UTC for wall patterns, epoch for timestamp patterns, via FilenameDate::legacy_datetime / legacy_timestamp at the seven consumer call sites. - Out-of-class files keep the global EXIF-wins waterfall unchanged. - CLAUDE.md waterfall section rewritten (step 0 = filename class; the EXIF-beats-filename note becomes out-of-class-only). Tests: five new waterfall-seam tests (wall no-evidence -> assumed_server; wall outranks EXIF with offset-tag evidence; wall GPS evidence; timestamp utc_direct; in-class video name resolves without exiftool) plus enum-shape assertions in every extractor test. Code-reviewed on both axes (standards: no violations, 3 of 4 P2 notes applied; spec: all acceptance criteria verified, no scope creep). 716 integration + 639 lib tests pass; fmt + clippy clean.
This commit is contained in:
1 parent
6f73a31e08
commit
a97bf53603
7 files changed
+358
-143
No files matched your search
@@ -374,6 +374,18 @@ per-tick drain can re-resolve weak entries when better tools become
|
||||
available, and so the UI/debug surface can answer "why did this photo
|
||||
land on this date?". Order:
|
||||
|
||||
0. **`filename` date class (ADR-0001, ticket #116)** —
|
||||
`extract_date_from_filename` in `memories.rs` returns a
|
||||
`FilenameDate`: wall-clock patterns (screenshot, dash, compact) or
|
||||
unix-timestamp patterns. A file whose name matches **any** pattern is
|
||||
*in the class*: the filename is the original date of record and wins
|
||||
*before* EXIF / container dates are consulted, inverting the global
|
||||
EXIF-wins rule for exactly those files (a renamed screenshot or a
|
||||
chat-export timestamp is the only honest date left). Wall patterns
|
||||
run the offset cascade over the file's own `OffsetTime*` / GPS
|
||||
evidence (empty evidence → server-zone assumption, so a class file
|
||||
always resolves); timestamp patterns are true instants outright
|
||||
(`utc_direct`, no offset). In-class files never hit exiftool.
|
||||
1. **`exif`** — kamadak-exif `DateTime` / `DateTimeOriginal`. Fast,
|
||||
in-process, image-only.
|
||||
2. **`exiftool`** — shell-out fallback for tags kamadak can't reach:
|
||||
@@ -395,17 +407,15 @@ land on this date?". Order:
|
||||
old server-local `-d %s` interpretation; the new-contract
|
||||
`date_utc` / `camera_offset_minutes` / `date_taken_tz_source`
|
||||
columns carry the true instant.
|
||||
3. **`filename`** — `extract_date_from_filename` in `memories.rs`
|
||||
matches screenshot, chat-export, and timestamp-named patterns.
|
||||
4. **`fs_time`** — `earliest_fs_time(metadata)` (earlier of created /
|
||||
modified). Last resort.
|
||||
3. **`fs_time`** — `earliest_fs_time(metadata)` (earlier of created /
|
||||
modified). Last resort. (The filename step sits at step 0 for
|
||||
in-class names; an out-of-class name matches nothing here.)
|
||||
|
||||
Notable behavior change vs. the pre-2026-05 request-time logic:
|
||||
**EXIF beats filename when both are present.** A photo named
|
||||
`Screenshot_2014-06-01.png` whose EXIF `DateTime` is 2021 now appears
|
||||
under 2021, not 2014 — on the theory that EXIF is more reliable than
|
||||
import-named filenames. The reverse case (no EXIF, filename has a
|
||||
date) is unchanged.
|
||||
**Out-of-class files keep EXIF-wins.** A photo named `IMG_1234.jpg`
|
||||
whose EXIF `DateTime` is 2021 appears under 2021 — EXIF
|
||||
`DateTimeOriginal` is more reliable than an import-time filename. The
|
||||
filename class (step 0) is the documented exception where the name is
|
||||
the original date itself.
|
||||
|
||||
The `backfill_missing_date_taken` drain (`src/backfill.rs`) runs every
|
||||
watcher tick alongside `backfill_unhashed_backlog` (also `src/backfill.rs`). It loads up to
|
||||
|
||||
Reference in new issue
Block a user