fix(review): harden write-back, confirmation gate, and edge cases

- write-back: call upsert_tag inside _apply_tag's try so a tag-create failure
  is caught per-asset and apply_all no longer aborts mid-batch (was P1)
- write-back: surface _pipeline/processed write failures in the result instead
  of discarding them (was reported as success)
- ui: add title to the high confidence badge so approve-high-confidence's
  pre-action count is non-zero; confirm() before single-cluster apply
- core: Store context manager; close DB connection even if a route raises;
  guard split_cluster against a first-member boundary (empty cluster); add
  writeback_log lookup index
- ingest: split thumbnail download/write error handling and clean up the
  .tmp file on a write failure
- tests: upsert/processed write-failure regression tests + split-guard test
This commit is contained in:
2026-06-27 17:54:38 +02:00
parent d67b677b6a
commit ae093881fa
8 changed files with 89 additions and 17 deletions
+13 -4
View File
@@ -45,14 +45,23 @@ def run_ingest(client, store, thumbs_dir, *, date_from=None, date_to=None,
if need_thumb:
try:
data = client.download_thumbnail(a["id"])
# Write to a temp path and os.replace into place so a failure
# never leaves a 0-byte <id>.jpg behind.
tmp_path = f"{thumb_path}.tmp"
except Exception:
log.exception("Thumbnail download failed for asset %s", a["id"])
continue
# Write to a temp path and os.replace into place so a failure
# never leaves a 0-byte <id>.jpg behind; clean up the temp file
# if the write itself fails (e.g. disk full).
tmp_path = f"{thumb_path}.tmp"
try:
with open(tmp_path, "wb") as f:
f.write(data)
os.replace(tmp_path, thumb_path)
except Exception:
log.exception("Thumbnail download failed for asset %s", a["id"])
log.exception("Thumbnail write failed for asset %s", a["id"])
try:
os.unlink(tmp_path)
except OSError:
pass
continue
store.upsert_asset(Asset(