Refuse oversized images on desktop and tighten placeholder cleanup (#198)

* Refuse oversized images on desktop and tighten placeholder cleanup

- Desktop refuses an image over 15 MB at pick in a cloud strategy, with
  web's message, before writing the file. An upload that can never
  succeed no longer holds a placeholder for a day. Local strategies
  still take any size.
- Restoring a deleted image element expects its image again only if the
  element was placed within the stale-upload window. An older one has
  uploaded or been swept, so a placeholder could only spin for a day.
- Deleting an image element keeps its placeholder while a lineup still
  shows the same image.
- Documents two gaps: a copy made after a placeholder was swept never
  gets the image, and the completion-retry window.

collectReferencedAssetIdsForStrategy and the stale-upload window move to
lib/imageAssets.ts so the placeholder cleanup can use them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Check only lineups, once per batch, before dropping a placeholder

Deleting an image element used to read every element and lineup in the
strategy to see whether its placeholder was still shown, once per
deleted image. A batch deleting many fresh images on a large strategy
could exceed Convex's per-mutation read limits and fail for good, and
the wide read set made unrelated collaborator edits conflict.

A placed image's id is its own element's publicId, so no other element
can show it; only lineups can. The check now reads the strategy's
lineups (through collectAssetIdsFromLineupPayload) at most once per
applyBatch, and only when a placeholder is at stake.

The 24h skip on restore now names element ops, matching the docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
bb89f7a8fdDara Adedeji committed on 9/26/2026, 12:17:01 AM· committed by GitHubparentad2cc41
7 files changedLine totals unavailable