Skip to content

Lists: add deterministic ordering to remaining paginated lists - #13214

Draft
ericholscher wants to merge 2 commits into
mainfrom
claude/pagination-ordering-fixes-xttjnn
Draft

Lists: add deterministic ordering to remaining paginated lists#13214
ericholscher wants to merge 2 commits into
mainfrom
claude/pagination-ordering-fixes-xttjnn

Conversation

@ericholscher

@ericholscher ericholscher commented Jul 29, 2026

Copy link
Copy Markdown
Member

Follow-up to #13210. Auditing every paginated list after that fix showed the subprojects page was one instance of a systemic pattern: the dashboard's shared list template and the APIs paginate whatever queryset a view provides, and several of those querysets have no ordering at all. Paginating an unordered queryset issues a separate LIMIT/OFFSET query per page with no ORDER BY, so rows can appear duplicated on one page and missing from another while the total count stays correct. DRF's LimitOffsetPagination slices the queryset directly, so the API endpoints never even emit UnorderedObjectListWarning.

Unordered lists fixed via Meta.ordering (no-op AlterModelOptions migrations, marked Safe.after_deploy()):

  • Notification (-created, newest first) — the five APIv3 notification list endpoints
  • EnvironmentVariable (name) — dashboard list and APIv3 endpoint
  • Team (name, pk tiebreaker since name is only unique per organization) — dashboard and APIv3 teams endpoints
  • WebHook, EmailHook, Integration, OrganizationOwner (pk) — their dashboard lists

Unordered lists fixed in views (models we don't own):

  • Organization members and project maintainers: User has no default ordering; both now order by the unique username
  • The two SocialAccount lists (GitHub App migration page, /api/v2/remote/account/): ordered by pk

Tie-vulnerable sorts that behave like the full bug in realistic conditions, fixed with a pk tiebreaker:

  • Projects dashboard and version list sort by latest build date with nulls_last — every never-built project/version ties on NULL, so any user with more than one page of never-built items got an undefined-order tail
  • Team members list — all pending invites tie on a null member

Why some orderings are pk and others -pk?

Direction never matters for the bug — any deterministic total order fixes pagination — so it's chosen per list for display:

  • Short settings-style lists with no natural sort key (webhooks, email notifications, integrations, owners, connected accounts) use ascending pk = creation order, which also matches the insertion order these lists effectively rendered before, so users see no reshuffle.
  • Feeds and "recent first" sorts tie-break with -pk, matching the primary sort's direction: notifications are -created, -pk (newest first even for same-instant rows), and the dashboard/version latest-build sorts append -pk so a just-created project surfaces at the top of the never-built tail instead of under years-old items.
  • Ascending sorts get ascending tiebreakers: ("name", "pk") for teams and environment variables, and pk after the ascending member sort for team members — duplicate names and pending invites list oldest first, consistent with an A→Z list.

The notifications golden response file is reordered because notifications now list newest-first. Remaining tie-vulnerable orderings with only microsecond-collision exposure (builds by -date, audit logs by -created, versions by -verbose_name, remote repositories/organizations by name) are left as-is, as is a possible queryset.ordered guardrail in a shared pagination class. The corporate repo needs the same audit for its own views (temporary-access and SSH-key lists, organizations viewset).


🤖 Generated with Claude Code

https://claude.ai/code/session_01BB6HHBjvZJsSgYC1aL1N2p


Generated by Claude Code

claude added 2 commits July 29, 2026 15:51
Several dashboard lists and API endpoints paginate querysets with no
ordering, so rows can appear duplicated or missing across pages (same
bug class as the subprojects list). Add Meta.ordering to the models
involved, order User-backed lists by username, and add pk tiebreakers
to sorts where many rows tie (never-built projects/versions, pending
team invites).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BB6HHBjvZJsSgYC1aL1N2p
Inherit TimeStampedModel.Meta on EnvironmentVariable and Integration so
the new ordering doesn't drop get_latest_by, and update the
notifications queryset test for the newest-first ordering.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BB6HHBjvZJsSgYC1aL1N2p
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants