Pre-fix the gate was `len(comments) >= limit`, which fired even when the
issue had EXACTLY <limit> comments. The "Show older" affordance appeared,
the user clicked, the next page fetched zero rows. User flagged it on
MUL-1857 — "this issue happens to have 30 comments; the button shouldn't
appear in that case."
The fix is the standard over-fetch probe: ask the SQL for limit+1 rows; if
it returned more than limit, drop the extra and report hasMore=true.
Otherwise hasMore=false.
- New helper `commentOverflow(rows, limit) -> ([]db.Comment, bool)` replaces
the count-based `hasMoreCommentsBeyond`. Works for both DESC (latest /
before) and ASC (after / around-newer) since both want "keep first
<limit>".
- All four mode handlers (latest, before, after, around) now ask for
limit+1 comments and route through the helper.
- Activities still cap at <limit> with no overflow probe — they don't gate
pagination (#1857), so the boundary doesn't matter for them.
Tests:
- TestCommentOverflow pins the truth table with the boundary case
("exactly limit comments" → hasMore=false).
- TestListTimeline_ExactlyLimitCommentsHidesShowOlder is the DB-backed
regression: 30 comments, limit=30, asserts has_more_before=false and
next_cursor=nil.
Co-authored-by: multica-agent <github@multica.ai>