Skip to content

fix(asks): a capped read of pending asks keeps the longest-waiting ones (#3679) - #3809

Merged
vybe merged 2 commits into
devfrom
fix/3679-pending-asks-oldest-first
Oct 19, 2026
Merged

vybe merged 2 commits into
devfrom
fix/3679-pending-asks-oldest-first

Conversation

@dolho

@dolho dolho commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

db/operator_queue.py::list_items ordered every row by sort_time descending within its priority, so pending asks came newest first. The Workspace Inbox and the operator queue each read one capped page of 200 and then show it oldest first. Once more asks were pending than the cap, the page they received had already dropped the asks that had waited longest, and neither client could show them.

The fix (one ORDER BY):

  • Pending rows sort oldest first (created_at ascending) after priority, so the cap drops the newest.
  • Ended rows keep their order (Credential-sync workflow missing for existing agents #627 AC6): newest-ended first, after every pending row.
  • There are now two age keys, one per group, each NULL across the other group. status_order already separates the groups, so NULL placement never decides an order. SQLite and PostgreSQL put NULLs at opposite ends, which is why this matters.
  • The direction is stated in the code that defines it, as the issue asks.

The Workspace's capped-read footer said "Showing your 200 most recent asks", which would now be wrong. It reads "Showing your first 200 asks: the ones waiting longest come first." The spec and feature-flows/workspace-inbox.md are updated to match.

Not changed: the ent#815 cursor walk (_walk_query). A walk visits every page, so no ask is cut, and its cursor predicate encodes the direction.

Fixes #3679

Tests

  • tests/unit/test_3679_pending_asks_oldest_first.py runs on real SQLite with ages set explicitly. On dev, 3 of its 4 cases fail; the priority case already passed. It checks:
  • portalInbox.mount.spec.js + portalInbox.spec.js: 203 passed.
  • test_ent428_workspace_asks.py::test_a_busy_fleet_does_not_crowd_out_one_client_ask is updated. Its fixture proves the addressee filter runs in SQL by building a page that crowds the client's ask out without the filter, and it relied on newest-first ordering. The client's ask is now raised after the noise. On the old ordering the fixture's own precondition trips, so this test also guards bug: a capped read of pending asks drops the longest-waiting ones (server sorts newest first, clients show oldest first) #3679. 26/26 pass.
  • Queue and asks unit tests: 2041 passed. Three failures fail identically on unchanged dev code and are not touched by this change:
  • Live reproduction on a local instance with the current ordering: an agent raised 5 asks in sequence, and GET /api/operator-queue?status=pending&limit=3 returned asks 5, 4, 3. The older ones were dropped.

Not run locally: the PostgreSQL track. The ORDER BY uses only CASE and ASC/DESC, both portable, and the NULL halves never meet across groups.

🤖 Generated with Claude Code

dolho and others added 2 commits October 19, 2026 16:45
…es (#3679)

list_items ordered every row by sort_time descending inside its priority,
so pending asks came newest first; the Workspace Inbox and the operator
queue each read one capped page (200) and show it oldest first, so past the
cap the asks that had waited longest were never shown. Pending rows now sort
oldest first; ended rows keep their newest-ended-first order (#627 AC6).
The two age keys are NULL across each other's group, so NULL placement
never decides an order on SQLite or PostgreSQL. The Workspace footer's
'200 most recent asks' note now says what the page holds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#3679)

The fixture proves the addressee filter runs in SQL by building a page that
crowds the client's ask out without it. It relied on newest-first ordering;
with pending oldest first, the client's ask is now raised after the noise.
On the old ordering its own precondition trips, so it also guards #3679.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@vybe vybe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge-train: batch validated on train/20261019-1651 (train PR #3818 green on Tier 1 + Tier 2)

@vybe
vybe merged commit cd8b1a4 into dev Oct 19, 2026
27 of 28 checks passed
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