7dcd2bc0f0
Reported: the index looked recreated on every keystroke, and switching library started it over. Both are the same bug, and it is in the ownership of the pass. searchEverywhere cancels and re-creates searchJob on every keystroke, and loadLibrary does the same with libraryJob. bringIndexCurrent was a suspend function called from inside those jobs, so the walk ran in the job that the next interaction cancelled. A cancelled pass never reaches endVolume, so the volume's stamp stayed old, so the next interaction found the index stale and started again from the first folder. With a 20 000-file volume on a phone, where a walk takes tens of seconds and typing takes milliseconds, the index could not finish while anyone was typing - and the progress counter restarting with every character was the visible half of it. The pass now has its own job on the view model: one at a time, shared by whoever asks, not cancelled by the screen that asked. Search does not wait for it once there is an answer to show (it did before, which queued the UI behind the walk), and when the pass lands it re-answers whatever is on screen - the query or the library - so "I just downloaded it" still works. A rebuild cancels any pass in flight and takes over: it is the one action that recovers from the index being wrong rather than old. Three tests, each standing inside a walk through a gated StorageSource: typing does not start a second pass, switching library does not start a second pass, and a finished pass answers the search again when it finds the file. 430 tests total.