The scan_folder resurrect path was unflagging every discarded photo on
every backend boot. start_initial_scan fires scan_all_source_roots on
container start, which fans out scan_folder for every source root,
which walked every file and silently set is_discarded=False on rows
whose file was still on disk -- so every deploy wiped the user's
discard decisions. Today's series of resurrect log lines for
admin/Photos came from that path, not from any actual user re-upload.
Gate the resurrect on os.path.getmtime(file) > discarded_at so the
WebDAV-DELETE-then-re-upload and trashbin-restore-via-PUT-overwrite
flows still trigger (those rewrite the file and bump mtime), but
routine sweeps respect the user's intent. Rows with discarded_at NULL
(legacy) fall through to skipped -- preserve intent over cleanup.
While there: add a Saved toast to the single-photo updateMutation.
The previous patch made cache writes synchronous, which removed the
visible save delay but also removed any signal that the change was
actually persisted. Toast picks a per-field label from the patched
keys (Title updated / Date updated / etc.) and falls back to a count
for multi-field saves.