The duplicate scan was one blocking request with a spinner: no progress,
a modal that could not be put away, and a result lost if the tab closed.
- POST /prompt_manager/scan_duplicates/stream starts the scan as a
background job (same ScanJob fan-out as the output scan) or attaches to
the running one; GET /prompt_manager/scan_duplicates/status reports it.
The job holds the duplicates lock, so deletes are refused while it runs.
- hashing runs on the configured worker threads and reports progress
about every percent
- the gallery modal shows a progress bar, closing it minimizes to a pill
that reopens it, results wait in the pill if the modal was closed, and a
reload re-attaches to a running scan
Infinite scrolling is a new Display Setting (off by default): the next page
is appended when the viewport nears the bottom, pagination controls hide,
and the load-more rule lives in list-state.js where it is unit tested.
Thumb-size buttons and the column setting no longer override each other.