Stage 1 of the virtualized-grid project (got-feedback/feedBack#636 item 3):
the data layer the DOM-recycling render window will build on, plus a latent
paging bug fixed on the way.
- Every grid sort now appends a unique `filename` tiebreak → a TOTAL order.
Without it, rows with an equal sort key (e.g. two songs by the same artist)
could be skipped or duplicated across OFFSET pages.
- query_page gains an opaque `after` keyset cursor: when supplied and the sort
can keyset (artist[-desc], title[-desc], recent), the page is fetched with a
WHERE-seek instead of OFFSET — O(page), independent of depth. The seek is
NULL-aware (NULLs first in ASC / last in DESC) so it's EXACTLY OFFSET-
equivalent; the legacy `dir=desc` shape is canonicalized so its cursor seeks
the right direction. Unknown/compound sorts + bad cursors fall back to OFFSET.
- /api/library exposes `after` + `next_cursor`. Only the true local provider is
handed a cursor (a collection may pin a different sort; remote don't keyset),
so both page by OFFSET safely.
- Composite (artist NOCASE, filename) / (title NOCASE, filename) /
(mtime, filename) indexes cover the order; `after` added to the optional
provider kwargs so legacy providers drop it.
Codex-reviewed; 3 findings fixed (dir=desc canonicalization, NULL-key seek,
cursor only for the local provider).
Tests: tests/test_library_keyset.py (keyset==OFFSET parity for 5 sorts, stable
tiebreak on equal keys, dir=desc, NULL sort keys, bad-cursor + compound-sort
fallback).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>