readNextTimelinePages can advance a stream cursor past records that were not added to the Timeline.
The problem appears when the remaining global record budget is smaller than the number of active streams. src/apps/timeline/timeline-data-source.ts sets pageLimit to at least 1, so it can fetch more records than the remaining budget. The loop stops accepting records when accepted >= remaining, but it still saves every fetched page's next_cursor.
For example, if one slot remains and two streams each return one record, Timeline keeps the first record and advances both cursors. The second record is skipped on the next "Load more" request.
Keep the global bound without advancing a cursor past an unconsumed record. Add a deterministic case with more active streams than remaining slots, then prove that repeated reads return every record exactly once.
This is separate from #11, which covers preserving loaded records when a later request fails.
readNextTimelinePagescan advance a stream cursor past records that were not added to the Timeline.The problem appears when the remaining global record budget is smaller than the number of active streams.
src/apps/timeline/timeline-data-source.tssetspageLimitto at least 1, so it can fetch more records than the remaining budget. The loop stops accepting records whenaccepted >= remaining, but it still saves every fetched page'snext_cursor.For example, if one slot remains and two streams each return one record, Timeline keeps the first record and advances both cursors. The second record is skipped on the next "Load more" request.
Keep the global bound without advancing a cursor past an unconsumed record. Add a deterministic case with more active streams than remaining slots, then prove that repeated reads return every record exactly once.
This is separate from #11, which covers preserving loaded records when a later request fails.