When asking an agent to debug a problem, it iterates through several steps — reproducing the bug, trying a fix, and iterating. Following an agent’s progress can be tricky as it iterates on solutions.sudocode gives the agent structure to remember what happens at each step, and gives you and your agent breadcrumbs to trace.
> User: We've got a bug in the workspace members list endpoint. Users are seeing duplicate members when they page through results. It seems intermittent — happens more when there are members with the same role. The endpoint is in src/routes/workspaces/members.ts and the query is in src/dao/member_dao.ts.⏺ Agent: Let me look at those files.⏺ Read(src/routes/workspaces/members.ts) ⎿ ...⏺ Read(src/dao/member_dao.ts) ⎿ ...⏺ Agent: I see the issue — the list query in MemberDAO orders by `role` and uses OFFSET/LIMIT pagination. If multiple members share the same role, the database doesn't guarantee a stable order between them, so rows can shift between pages.> User: That matches what we're seeing. Can you write an issue to reproduce this in tests first? Then fix it. Keep track of a chain of issues until we fix the root problem.
⏺ Agent: I'll start with a reproduction test.⏺ plugin:sudocode:sudocode - upsert_issue (MCP) (title: "Reproduce duplicate members pagination bug in tests", description: "Members list endpoint returns duplicates when paging through results where multiple members share the same role. ## Reproduction steps - Seed 10+ members with the same role in a workspace - Paginate through with page_size=3 - Collect all returned member IDs across pages - Assert no duplicates ## Expected Test should FAIL — confirming the bug exists before we fix it. ## Files - src/dao/member_dao.ts (the query) - tests/dao/member_dao.test.ts (new test)", status: "open", priority: 1, tags: ["bug", "pagination"]) ⎿ { "id": "i-2r5t", ... }⏺ plugin:sudocode:sudocode - upsert_issue (MCP) (issue_id: "i-2r5t", status: "in_progress")⏺ Edit(tests/dao/member_dao.test.ts) ⎿ Added test: "should not return duplicate members across pages"⏺ Bash(npm test -- tests/dao/member_dao.test.ts) ⎿ FAIL: expected 0 duplicates, found 3⏺ plugin:sudocode:sudocode - add_feedback (MCP) (to_id: "i-2r5t", content: "Reproduction confirmed. Test seeds 12 members all with role='viewer', paginates with page_size=3. Found 3 duplicate IDs across pages. The ORDER BY role clause has no tiebreaker, so Postgres returns rows in arbitrary order within the same role.", type: "comment")⏺ plugin:sudocode:sudocode - upsert_issue (MCP) (issue_id: "i-2r5t", status: "closed")⏺ Agent: Bug reproduced and test is failing as expected. Moving on to the fix.
⏺ plugin:sudocode:sudocode - upsert_issue (MCP) (title: "Fix unstable sort in member list pagination", description: "The member list query in MemberDAO orders by `role` only, which produces unstable ordering when multiple members share a role. This causes duplicates across OFFSET/LIMIT pages. ## Fix Add `id` as a secondary sort column to guarantee stable ordering. ## Verification Reproduction test from [[i-2r5t]] should pass after this fix. ## Files - src/dao/member_dao.ts", status: "open", priority: 1, tags: ["bug", "pagination"]) ⎿ { "id": "i-6h3k", ... }⏺ plugin:sudocode:sudocode - link (MCP) (from_id: "i-2r5t", to_id: "i-6h3k", type: "related")⏺ plugin:sudocode:sudocode - upsert_issue (MCP) (issue_id: "i-6h3k", status: "in_progress")⏺ Edit(src/dao/member_dao.ts) ⎿ Changed ORDER BY role to ORDER BY role, id⏺ Bash(npm test -- tests/dao/member_dao.test.ts) ⎿ PASS⏺ plugin:sudocode:sudocode - add_feedback (MCP) (to_id: "i-6h3k", content: "Added `id` as tiebreaker to ORDER BY clause. Repro test passes now. Change is one line in the listMembers query.", type: "comment")⏺ Agent: Fix is in and the reproduction test passes. While I was in there, I noticed something — there's also a cursor-based pagination path in the same DAO that has the same problem. Want me to handle that too?> User: Yeah, track it and fix it.
⏺ plugin:sudocode:sudocode - upsert_issue (MCP) (title: "Fix unstable sort in cursor-based member pagination", description: "Same root cause as [[i-6h3k]] — the cursor-based pagination path in MemberDAO.listMembersCursor() also orders by `role` without a tiebreaker. The cursor comparison uses `role` as the cursor value, which is not unique. ## Fix - Add `id` to the ORDER BY - Update cursor to be a composite of (role, id) - Update the WHERE clause to use composite cursor comparison ## Files - src/dao/member_dao.ts", status: "open", priority: 1, tags: ["bug", "pagination"]) ⎿ { "id": "i-8m1w", ... }⏺ plugin:sudocode:sudocode - link (MCP) (from_id: "i-6h3k", to_id: "i-8m1w", type: "related")⏺ plugin:sudocode:sudocode - upsert_issue (MCP) (issue_id: "i-8m1w", status: "in_progress")⏺ Edit(src/dao/member_dao.ts) ⎿ Updated listMembersCursor() with composite cursor⏺ Edit(tests/dao/member_dao.test.ts) ⎿ Added test: "cursor pagination should not return duplicates"⏺ Bash(npm test -- tests/dao/member_dao.test.ts) ⎿ PASS (3 tests)⏺ plugin:sudocode:sudocode - add_feedback (MCP) (to_id: "i-8m1w", content: "Cursor pagination fixed. Changed cursor from just `role` to a composite `role:id` string. The WHERE clause now does a tuple comparison: (role, id) > (cursor_role, cursor_id). Added a dedicated test that seeds members with identical roles and verifies no duplicates across cursor pages.", type: "comment")⏺ plugin:sudocode:sudocode - upsert_issue (MCP) (issue_id: "i-6h3k", status: "closed")⏺ plugin:sudocode:sudocode - upsert_issue (MCP) (issue_id: "i-8m1w", status: "closed")⏺ Agent: All three issues closed: - i-2r5t: Reproduced the pagination duplicate bug - i-6h3k: Fixed OFFSET/LIMIT pagination sort order - i-8m1w: Fixed cursor-based pagination sort order