Every catalog row, ordered by id.
Insert or replace many rows and persist once.
putCatalogEntry rewrites the whole catalog on every call, so building an
index a record at a time wrote it N times — 5.6 MiB to land a 153 KiB file
for 200 records, quadratic in the corpus.
Replace every catalog row with entries and persist, without reading what is
there. That is what a rebuild needs: ka reindex read the old catalog in order
to clear it, so a corrupt catalog was the one thing it could not repair.
Run
workwith catalog writes deferred, and persist the catalog once when it returns — also when it throws, so an interrupted run keeps what it indexed.putCatalogEntrypersists on every call, which is the right default for a one-off caller and the wrong shape for a sync: indexing a record at a time re-read and rewrote the whole catalog per record, quadratic in the corpus. The pipeline wraps its record loop in this; nested batches flush once, at the outermost, and concurrent ones each at their own end.