Keyset Without a Tiebreak — JavaScript Bug Hunt
Inspired by the pagination bug that silently swallows rows on every busy platform: keyset pagination on created_at alone.
- Language: JavaScript
- Layer: Database
- Difficulty: Hard
- Concepts: Pagination, Ordering
- Modelled on: Data-export pipelines
- Visible tests: rows after the cursor timestamp appear; same-timestamp siblings are not skipped; the limit caps the page
- Reward: 50 XP for a complete fix
Briefing
Inspired by the pagination bug that silently swallows rows on every busy platform: keyset pagination on created_at alone. When several rows share a timestamp (bulk imports do this constantly), the next page skips their siblings.
The cursor carries (created, id) — use both.
Bug report
BUG-KEYSET · Priority: High · Reported by: data eng
nextPage(rows, cursor, limit) — rows pre-sorted by (created, id) ascending:
- return up to limit rows strictly AFTER the cursor position
- "after" means created > cursor.created, OR equal created AND id > cursor.id
Observed: three rows imported in the same second; page 2 starts after the whole second — two rows never appear anywhere.
Logs
[export] total rows 9, paginated union 7 (2 lost at ts=500)The code as shipped
src/query/keyset.js (editable)
// Keyset pagination over rows sorted by (created, id).
exports.nextPage = function (rows, cursor, limit) {
var out = [];
for (var i = 0; i < rows.length && out.length < limit; i++) {
if (rows[i].created > cursor.created) {
out.push(rows[i]);
}
}
return out;
};
Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More JavaScript bug hunts.