Skip to content

fix(queue): prevent applyQueueDropPolicy from selecting in-flight items as overflow victims#103284

Merged
steipete merged 2 commits into
openclaw:mainfrom
tzy-17:fix/103246-queue-drop-inflight
Jul 10, 2026
Merged

fix(queue): prevent applyQueueDropPolicy from selecting in-flight items as overflow victims#103284
steipete merged 2 commits into
openclaw:mainfrom
tzy-17:fix/103246-queue-drop-inflight

Conversation

@tzy-17

@tzy-17 tzy-17 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

While a followup is executing, its object stays in the shared queue array until delivery succeeds. Overflow eviction, drop:new admission, and reported queue depth previously treated that active object as pending work. Under a burst, the same message could therefore be delivered and also recorded as dropped; non-summary policies could complete its lifecycle before delivery finished.

Closes #103246

Why This Change Was Made

The queue now owns one identity set for items currently being delivered. A shared intersection-based counter excludes only active identities that are still present in the queue array; this matters because collect admission can remove active group items before the awaited delivery settles. Old and summarize policies skip those identities when selecting victims, drop:new uses the same pending count before lifecycle publication, and public queue depth reports the same population.

Single-item removal remains by reference and still happens only after successful delivery, preserving the retry and concurrent-mutation fix from #91450. Collect groups receive the same protection for their full awaited delivery window.

User Impact

  • Active messages are no longer reported as unanswered overflow victims.
  • Queue lifecycles do not complete early because of overflow eviction.
  • drop:new admits up to the configured number of genuinely pending messages while another message is active.
  • Queue status reports pending depth rather than counting work already executing.

Evidence

  • Exact reviewed head: a557ff132ef88b144315ea5ccb25c5c8f2e67341.
  • Sanitized AWS Crabbox cbx_76d796ba2956, public networking, no Tailscale, no IAM instance profile:
    • run_0e5b047f644f: 31/31 tests passed across queue-helpers.test.ts, the production-owner queue.in-flight.test.ts, and reply-flow.test.ts.
    • run_a4b0461ad81c: pnpm check:changed passed the core/coreTests lanes, production and test tsgo checks, changed-file lint, and repository guards.
  • GitHub CI run 29070791862 passed on the exact head, including build artifacts, lint, production/test types, and all Node shards (11,628 passed, 3 skipped in the full Node lane).
  • Fresh full-branch autoreview: clean, no accepted/actionable findings, overall correctness 0.97.

Co-Authored-By: Claude Opus 4.7 [email protected]

@steipete steipete self-assigned this Jul 10, 2026
tzy-17 and others added 2 commits July 10, 2026 01:09
…ms as overflow victims

When a burst of inbound messages hits the followup queue cap while the
head item is mid-delivery, applyQueueDropPolicy can select that same
in-flight item as an overflow victim. With the default
dropPolicy: "summarize", the in-flight item ends up recorded in the
overflow summary as dropped even though it is still being delivered,
producing a contradictory record where the same message is both
answered and reported as unanswered-due-to-overflow.

The fix introduces an optional `inFlight` Set parameter to
applyQueueDropPolicy and drainNextQueueItem. The followup queue state
now owns a shared inFlight set that is:
- Populated by drainNextQueueItem during the await run(next) window
- Populated by the collect-merge drain path for activeGroupItems
- Passed to applyQueueDropPolicy in enqueueFollowupRun

The drop policy now computes an effective queue length that excludes
in-flight items, and skips them when selecting splice victims.

Fixes openclaw#103246

Co-Authored-By: Claude Opus 4.7 <[email protected]>
@steipete
steipete force-pushed the fix/103246-queue-drop-inflight branch from ae907e0 to a557ff1 Compare July 10, 2026 05:11
@steipete

Copy link
Copy Markdown
Contributor

Land-ready proof for a557ff132ef88b144315ea5ccb25c5c8f2e67341:

  • Reworked the patch around one queue-owned identity set and one intersection-based pending counter. Old/summarize eviction, drop:new preflight, overflow count, and reported depth now use the same population.
  • Preserved the fix(reply-queue): remove the drained item by reference instead of front index #91450 invariant: a single item is removed by identity only after successful delivery; failure leaves it queued for the existing retry path.
  • Added real queue-owner coverage for old, summarize, and new policies; single and collect drains; lifecycle completion timing; reported depth; and collect admission where active identities have already left the item array.
  • Sanitized AWS Crabbox cbx_76d796ba2956 used public networking with no Tailscale and no IAM instance profile. run_0e5b047f644f passed 31/31 focused helper/owner/reply-flow tests. run_a4b0461ad81c passed pnpm check:changed for core/coreTests, tsgo production/test checks, lint, and guards. The lease was released after proof.
  • Exact-head GitHub CI: https://github.com/openclaw/openclaw/actions/runs/29070791862 — green, including build, lint, production/test types, and all Node shards.
  • Fresh full-branch autoreview: clean, no accepted/actionable findings; overall correctness 0.97.

Provenance: the front-splice overflow rule dates to eb8a0510e031; #91450 by @yetval correctly changed post-await removal to identity-based removal and exposed this remaining overlap rather than causing it. This PR keeps that fix intact and closes the sibling invariant comprehensively.

No known proof gaps. Thanks @tzy-17 for identifying and implementing the core identity-set direction.

@steipete
steipete merged commit 2f7e2ae into openclaw:main Jul 10, 2026
112 of 114 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
…ms as overflow victims (openclaw#103284)

* fix(queue): prevent applyQueueDropPolicy from selecting in-flight items as overflow victims

When a burst of inbound messages hits the followup queue cap while the
head item is mid-delivery, applyQueueDropPolicy can select that same
in-flight item as an overflow victim. With the default
dropPolicy: "summarize", the in-flight item ends up recorded in the
overflow summary as dropped even though it is still being delivered,
producing a contradictory record where the same message is both
answered and reported as unanswered-due-to-overflow.

The fix introduces an optional `inFlight` Set parameter to
applyQueueDropPolicy and drainNextQueueItem. The followup queue state
now owns a shared inFlight set that is:
- Populated by drainNextQueueItem during the await run(next) window
- Populated by the collect-merge drain path for activeGroupItems
- Passed to applyQueueDropPolicy in enqueueFollowupRun

The drop policy now computes an effective queue length that excludes
in-flight items, and skips them when selecting splice victims.

Fixes openclaw#103246

Co-Authored-By: Claude Opus 4.7 <[email protected]>

* fix(queue): align pending depth with active deliveries

---------

Co-authored-by: Claude Opus 4.7 <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

queue-helpers: applyQueueDropPolicy can drop the item currently mid-delivery, producing a duplicate/contradictory overflow record

2 participants