Three features over a shared schema migration.
Collections: a tree of manual collections plus smart collections whose
membership *is* their stored selector. Dropping images onto a smart
collection is refused rather than silently discarded, so the UI can say why
the drop did nothing — member rows there would be a second source of truth
that nothing reads.
Ratings: the star and pick/reject axes, kept independent.
Trash: soft delete to a folder, then permanent delete.
Catalog::open now backfills after migrating. A migration adds a column but
cannot know what the value should be for rows that already existed;
backfilling on open is what stops those rows being silently partial.
Timeline queries exclude shadowed JPEGs, which would otherwise double every
paired shot in the histogram, and gain a range-bounded variant so zooming in
returns finer buckets rather than the same coarse ones with the ends cropped.
Assisted-by: LLM