With no collection given, the listing walked every collection in the repo,
took the first limit records of each, concatenated them, and answered
cursor: null. Two problems in one: the response could be
collections × limit records however small a limit the caller asked for,
and a caller had no way to request the rest or to tell that a rest existed.
A short page is the only signal a client has that it has seen everything,
and this mode never sent one -- it answered identically whether it had
returned the whole repo or a fraction of it.
limit is now the total, and a full page carries a cursor naming the last
record delivered: <collection>\u{1}<rkey>. The separator is a control
character because an NSID cannot contain one and neither can an rkey, so the
split is unambiguous where a / or a . would not be -- both appear in the
values being joined.
The cursor names a record rather than a collection so a page that stops mid-collection resumes mid-collection. Naming only the collection would either repeat everything already delivered from it or skip the remainder, depending on which way the ambiguity was resolved.
Collections are walked in ascending order regardless of reverse, which now
orders records within a collection only. A cursor has to name a position in
a stable sequence, and a reverse that flipped the outer order as well
would move every position each time the flag changed.
Takedown filtering still runs per collection, so a page can come back shorter than the limit even when more records follow. That is the same behaviour the single-collection mode has always had, and it is why the cursor is suppressed on a short page rather than on an empty one.