A bulk import never says how many scans it could not read EXIF from #148

Open
opened 2026-08-07 04:32:01 +00:00 by claude-bot · 0 comments

Severity: LOW on its own, but it is how #145 survived

Split out of #145 rather than bundled into it, because it is a reporting change with its own contract to cross.

The gap

When extract_exif fails on a file, the failure is recorded on the audit event (exif_status, exif_error — added by #65 precisely so "could not be read" stays distinguishable from "there was none") and logged at WARNING. Nothing aggregates it.

One correction to what #145 assumed, established while fixing it: the warning is not only in the ledger. extract_exif logs it, and because app/cli/ingest_folder.py never calls configure_logging, Python's logging.lastResort handler sends it to stderr. So during a real import it would have appeared — as a single unformatted line, interleaved among thousands of per-file progress lines. Which is why it was effectively invisible, and why #145 went unnoticed until an unrelated container build tripped over it.

That is the actual failure mode worth fixing: not that the fact was unrecorded, but that a systematic problem — every TIFF in the collection failing the same way — looked identical to routine per-file noise.

Scope

Surface it in the one thing an operator actually reads: BatchReport.report(), as an exif_unreadable N term alongside the existing outcome counts.

The seam is clean but crosses a contract, which is why this is its own issue:

  • ingest_photo already has the exif result in hand (app/services/ingest.py, where the audit context is built)
  • IngestResult does not carry it — needs a field
  • FileOutcome in app/services/ingest_batch.py needs to record it
  • _SUMMARY_ORDER needs the term

Several existing tests assert on that contract, so it wants its own tests rather than being smuggled into another change.

Cheap interim, if this is not picked up soon: have ingest_folder call configure_logging() so the warning is at least formatted like every other log line rather than arriving through lastResort. That is a one-liner and strictly an improvement.

Explicitly not wanted: a per-photo badge

exif_status is a property of the read, not of the photograph, and the overwhelming majority of scanned prints legitimately have no EXIF at all — a print from 1962 has none, and saying so on every tile would be noise attached to the normal case. The answerable question is "does this archive have a systematic reading problem", which is operator-level and belongs in the import summary.

A dashboard count would also need a real column, since the status currently lives inside the audit event's JSON context.

References

  • #145 (the bug this failed to surface), #65 (why the status is recorded at all)
  • backend/app/services/ingest_batch.pyBatchReport.report(), FileOutcome, _SUMMARY_ORDER
  • backend/app/cli/ingest_folder.py — no configure_logging() call
## Severity: LOW on its own, but it is how #145 survived Split out of #145 rather than bundled into it, because it is a reporting change with its own contract to cross. ## The gap When `extract_exif` fails on a file, the failure is recorded on the audit event (`exif_status`, `exif_error` — added by #65 precisely so "could not be read" stays distinguishable from "there was none") and logged at WARNING. **Nothing aggregates it.** One correction to what #145 assumed, established while fixing it: the warning is not *only* in the ledger. `extract_exif` logs it, and because `app/cli/ingest_folder.py` never calls `configure_logging`, Python's `logging.lastResort` handler sends it to stderr. So during a real import it *would* have appeared — as a single unformatted line, interleaved among thousands of per-file progress lines. Which is why it was effectively invisible, and why #145 went unnoticed until an unrelated container build tripped over it. That is the actual failure mode worth fixing: not that the fact was unrecorded, but that a *systematic* problem — every TIFF in the collection failing the same way — looked identical to routine per-file noise. ## Scope Surface it in the one thing an operator actually reads: `BatchReport.report()`, as an `exif_unreadable N` term alongside the existing outcome counts. The seam is clean but crosses a contract, which is why this is its own issue: - `ingest_photo` already has the `exif` result in hand (`app/services/ingest.py`, where the audit context is built) - `IngestResult` does not carry it — needs a field - `FileOutcome` in `app/services/ingest_batch.py` needs to record it - `_SUMMARY_ORDER` needs the term Several existing tests assert on that contract, so it wants its own tests rather than being smuggled into another change. **Cheap interim, if this is not picked up soon:** have `ingest_folder` call `configure_logging()` so the warning is at least formatted like every other log line rather than arriving through `lastResort`. That is a one-liner and strictly an improvement. ## Explicitly not wanted: a per-photo badge `exif_status` is a property of the *read*, not of the photograph, and the overwhelming majority of scanned prints legitimately have no EXIF at all — a print from 1962 has none, and saying so on every tile would be noise attached to the normal case. The answerable question is "does this archive have a systematic reading problem", which is operator-level and belongs in the import summary. A dashboard count would also need a real column, since the status currently lives inside the audit event's JSON context. ## References - #145 (the bug this failed to surface), #65 (why the status is recorded at all) - `backend/app/services/ingest_batch.py` — `BatchReport.report()`, `FileOutcome`, `_SUMMARY_ORDER` - `backend/app/cli/ingest_folder.py` — no `configure_logging()` call
Sign in to join this conversation.
No description provided.