Skip to main content

Overview

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.

The Scenario

Users see duplicate entries when paging through the workspace members list API. You suspect it’s related to the sort order.

Describing the bug

Open your agent and describe what you’re seeing.
> 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.

Reproducing the bug in tests

⏺ 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.

Fixing the root cause

⏺ 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

What you get

Three linked issues tracing the full investigation:
  • i-2r5t (reproduce) → i-6h3k (fix OFFSET/LIMIT) → i-8m1w (fix cursor-based)
Each has feedback documenting what was found and decided. If someone later asks “why does the cursor use a composite format?”, the trail is there.

Key Takeaways

The reproduction issue is separate from the fix — the test is its own tracked artifact.
Each issue is a step in the debugging process. The links between them tell the story.
The cursor pagination bug wasn’t part of the original report. A separate linked issue keeps it visible instead of buried in a comment.