fix: make session list LIMIT bound sessions, not joined rows - #787
fix: make session list LIMIT bound sessions, not joined rows#787grvijayan wants to merge 6 commits into
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR fixes cursor-based pagination for ListSessions across Postgres, SQLite, and Spanner by ensuring LIMIT applies to sessions (the base table) rather than to joined rows from the one-to-many checks join, preventing undersized pages, withheld next cursors, and truncated factor lists.
Changes:
- Reworked the per-dialect session list SQL to page via an inner subquery over
sessions(with filter/cursor/order/limit), then joinuser_agentsandchecksonto that page. - Re-applied
ORDER BYin the outer query to preserve row order forscanSessions(which derives session order from row iteration order). - Added integration tests covering multi-check sessions to ensure page fullness, cursor issuance, no unreachable sessions, and complete factor lists.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| internal/storage/v2/stmttest/session_multicheck_test.go | Adds integration coverage proving LIMIT bounds sessions (not joined rows) and factors remain complete under pagination. |
| internal/storage/v2/dialect/sqlite/session.go | Wraps session paging in an inner sessions subquery and applies outer ORDER BY after joins to preserve scan order. |
| internal/storage/v2/dialect/spanner/session.go | Same subquery-based paging shape for Spanner to prevent joined-row limiting and preserve ordering post-join. |
| internal/storage/v2/dialect/postgres/session.go | Same subquery-based paging shape for Postgres to ensure correct session-bounded pagination and complete factor lists. |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes #782
The session list query joins
sessionswithuser_agentsandchecks, and the compiledLIMITwas appended to the joined statement. The checks join is one-to-many, so the limit bounded session-check rows instead of sessions: a session with several checks shrank the page below the requested size, thelen(sessions) == limitcursor gate then withheld the next cursor (making later sessions unreachable), and a cut landing inside a session's check rows truncated its factor list.The query now pages in an inner subquery over
sessionsalone — filter, cursor,ORDER BYandLIMITcompile into it — and the joins run against that page. This works because everysessionSchemafield is a sessions column. The outer statement repeats theORDER BY, since the joins don't preserve the subquery's order andscanSessionsderives session order from row order. Same shape in all three dialects;compileReadis unchanged.New integration coverage in
session_test.go, red without the fix on all assertions:TestSessionStatements_List_LimitBoundsSessions— three two-check sessions paged with limit 2 must fill the page, issue a cursor, and return every session exactly once in ID order.TestSessionStatements_List_LimitKeepsFactorsComplete— a two-check session listed with limit 1 must keep both factors.The tests are order-independent (every session carries two checks) and avoid the helpers #781 introduces, so the branches merge cleanly in either order.
Verified: sqlite integration suite and untagged unit tests pass locally; postgres and spanner run in CI.
🤖 Generated with Claude Code