Repository navigation
fix: end /next drains that re-offer an already-skipped message - #753
Closed
bandzalkin wants to merge 1 commit into
Closed
bandzalkin wants to merge 1 commit into
bandzalkin wants to merge 1 commit into
Conversation
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 8, 2026
Squashed from band-ai#753 at c02eb66. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 8, 2026
Squashed from band-ai#730 at fb7403a, resolved over band-ai#753: a locally skipped /next head now hands the drain to the actionable snapshot, so band-ai#753's re-offer guard is a backstop and its wedge tests assert one /next poll; the sync point still accepts a no-progress result but only once the message is terminal. Upstream-PR: band-ai#730
bandzalkin
added a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 8, 2026
Squashed from band-ai#753 at c02eb66. Upstream-PR: band-ai#753
bandzalkin
added a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 8, 2026
Squashed from band-ai#730 at fb7403a, resolved over band-ai#753: a locally skipped /next head now hands the drain to the actionable snapshot, so band-ai#753's re-offer guard is a backstop and its wedge tests assert one /next poll; the sync point still accepts a no-progress result but only once the message is terminal. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 8, 2026
Squashed from band-ai#753 at c02eb66. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 8, 2026
Squashed from band-ai#730 at fb7403a, resolved over band-ai#753: a locally skipped /next head now hands the drain to the actionable snapshot, so band-ai#753's re-offer guard is a backstop and its wedge tests assert one /next poll; the sync point still accepts a no-progress result but only once the message is terminal. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#753 at c02eb66. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#730 at fb7403a, resolved over band-ai#753: a locally skipped /next head now hands the drain to the actionable snapshot, so band-ai#753's re-offer guard is a backstop and its wedge tests assert one /next poll; the sync point still accepts a no-progress result but only once the message is terminal. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#753 at c02eb66. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#730 at fb7403a, resolved over band-ai#753: a locally skipped /next head now hands the drain to the actionable snapshot, so band-ai#753's re-offer guard is a backstop and its wedge tests assert one /next poll; the sync point still accepts a no-progress result but only once the message is terminal. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#753 at c02eb66. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#730 at fb7403a, resolved over band-ai#753: a locally skipped /next head now hands the drain to the actionable snapshot, so band-ai#753's re-offer guard is a backstop and its wedge tests assert one /next poll; the sync point still accepts a no-progress result but only once the message is terminal. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#753 at c02eb66. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#730 at fb7403a, resolved over band-ai#753: a locally skipped /next head now hands the drain to the actionable snapshot, so band-ai#753's re-offer guard is a backstop and its wedge tests assert one /next poll; the sync point still accepts a no-progress result but only once the message is terminal. Upstream-PR: band-ai#730
bandzalkin
added a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#753 at c02eb66. Upstream-PR: band-ai#753
bandzalkin
added a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#730 at fb7403a, resolved over band-ai#753: a locally skipped /next head now hands the drain to the actionable snapshot, so band-ai#753's re-offer guard is a backstop and its wedge tests assert one /next poll; the sync point still accepts a no-progress result but only once the message is terminal. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#753 at c02eb66. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 9, 2026
Squashed from band-ai#730 at fb7403a, resolved over band-ai#753: a locally skipped /next head now hands the drain to the actionable snapshot, so band-ai#753's re-offer guard is a backstop and its wedge tests assert one /next poll; the sync point still accepts a no-progress result but only once the message is terminal. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 10, 2026
Squashed from band-ai#753 at c02eb66. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 10, 2026
Squashed from band-ai#730 at fb7403a, resolved over band-ai#753: a locally skipped /next head now hands the drain to the actionable snapshot, so band-ai#753's re-offer guard is a backstop and its wedge tests assert one /next poll; the sync point still accepts a no-progress result but only once the message is terminal. Upstream-PR: band-ai#730
The /next catch-up loops polled until the endpoint yielded nothing. A message skipped from local knowledge alone -- completed, permanently failed, or the agent's own -- never changes its platform state, so once the processed-ack retry budget exhausted and recorded local completion without a durable mark, /next kept returning that same oldest message: the drain spun on it and newer REST-only backlog starved behind it. Classify those skips as BacklogProcessResult.NO_PROGRESS and end a drain that re-receives a message it already skipped in the same pass, the way the stop and permanently-failed guards already end a drain. Retryable outcomes -- a handler failure with attempt budget left, a pending processed ack, an unacquired claim -- keep their in-drain retry semantics unchanged.
AlexanderZ-Band
force-pushed
the
fix/processed-ack-resync-livelock
branch
from
October 10, 2026 06:24
c02eb66 to
6f5df16
Compare
bandzalkin
added a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 10, 2026
Squashed from band-ai#753 at 6f5df16. Upstream-PR: band-ai#753
bandzalkin
added a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 10, 2026
Squashed from band-ai#730 at adebc7d; preserves band-ai#753 terminal sync handling and removes a duplicate recovery wiring assertion in favor of behavioral recovery coverage. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 10, 2026
Squashed from band-ai#753 at 6f5df16. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 10, 2026
Squashed from band-ai#730 at adebc7d; preserves band-ai#753 terminal sync handling and removes a duplicate recovery wiring assertion in favor of behavioral recovery coverage. Upstream-PR: band-ai#730
bandzalkin
added a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 11, 2026
Squashed from band-ai#753 at 6f5df16. Upstream-PR: band-ai#753
bandzalkin
added a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 11, 2026
Squashed from band-ai#730 at adebc7d; preserves band-ai#753 terminal sync handling and removes a duplicate recovery wiring assertion in favor of behavioral recovery coverage. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 11, 2026
Squashed from band-ai#753 at 6f5df16. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 11, 2026
Squashed from band-ai#730 at adebc7d; preserves band-ai#753 terminal sync handling and removes a duplicate recovery wiring assertion in favor of behavioral recovery coverage. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 11, 2026
Squashed from band-ai#753 at 6f5df16. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 11, 2026
Squashed from band-ai#730 at adebc7d; preserves band-ai#753 terminal sync handling and removes a duplicate recovery wiring assertion in favor of behavioral recovery coverage. Upstream-PR: band-ai#730
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 11, 2026
Squashed from band-ai#753 at 6f5df16. Upstream-PR: band-ai#753
github-actions Bot
pushed a commit
to bandzalkin/band-sdk-python
that referenced
this pull request
Oct 11, 2026
Squashed from band-ai#730 at adebc7d; preserves band-ai#753 terminal sync handling and removes a duplicate recovery wiring assertion in favor of behavioral recovery coverage. Upstream-PR: band-ai#730
Collaborator
|
Closing as superseded by #761. Current main already detects a repeated locally nonrunnable This PR would duplicate that no-spin behavior. It also cannot unblock later REST-only work behind a server-retained head; that remaining recovery problem needs a separate, current-main design and is being considered in #730. |
bandzalkin
added a commit
that referenced
this pull request
Oct 13, 2026
Refresh #730 onto current upstream. Collect complete unfiltered chronological pages before claims; retain failed heads, eligible delivery order, terminal WebSocket handoff and current recovery/admission ownership. Source-Base: 55c70f2 Source-Head: adebc7d Applied-Over: cd6bde7 Conflict-Notes: keep authoritative /next and stopped-room 204 gating, no filtered processing pre-sweep; reuse shared nonrunnable predicate instead of #753 NO_PROGRESS bookkeeping; fold 0537758 snapshot revision fence into explicit recovery outcomes; preserve accepted claim, pending input, acknowledgement, #776 STOP and TurnTask custody. CHANGELOG.md excluded. Verification: parent assembled HTTP-boundary/custody proof 589 passed; #761 plus refreshed #730 covers #753 no-spin behavior. Source hunk ledger retained in u3-preparation/fork. Upstream-PR: #730
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A room's
/nextcatch-up loops could livelock, pinning the room's REST backlog behind one message forever (busy/nextpolling, no durable progress)._retry_processed_ack(src/band/runtime/execution.py) deliberately converts an exhausted processed-ack retry budget into local completion: the turn ran, so re-running it could duplicate its side effects, and blocking forever on the failed ack would starve every newer message. But from that moment on:processing), so/nextkeeps returning it as the oldest not-processed message;_process_backlog_messageadvances it from the local completed marker without touching the platform;_synchronize_with_nextand_resync_pending_messagesreadADVANCEDas server-side progress and loop until/nextyieldsNone.Result: a drain that spins on one message it can never retire, and a REST-only backlog that never gets past it. This also widens from a single trigger to whole bursts for agents that merge waiting messages into one turn (band-agent's merged turns ack every merged message on the turn's tools; one lost ack wedges one fetch each).
Fix
Classify the local-knowledge skips (locally completed, permanently failed, own echo) as a new
BacklogProcessResult.NO_PROGRESS, and have both drain loops end a drain that re-receives a message they already skipped in the same pass — the same way the existingstoppedandpermanently-failedguards end a drain without durable completion.Retryable outcomes are untouched: a handler failure with attempt budget left, a pending processed-ack, or an unacquired claim keep today's in-drain retry semantics (new test
test_startup_sync_retries_failed_message_in_same_drainpins this; the guard records onlyNO_PROGRESS, never those).Scope and limits
/nextcontract. New WS-pushed messages process normally while a wedged message waits to be retired (platform stale-processing re-serve, local completion cache eviction, or restart).BacklogProcessResultis internal.Tests
tests/runtime/test_resync.py: two wedge tests (repeating/next+ locally completed message → both drains return synced after two fetches; they fail pre-fix by spinning to a 10-fetch cap) and the retry-preservation test.tests/runtime/test_execution.py: two local-skip assertions updated to the newNO_PROGRESSclassification (behavioral assertions unchanged).ruff check,ruff format --check,pyrefly check,pytestfull unit suite — 6703 passed / 711 skipped;pre-commit run --all-filesclean.ADVANCEDresults and deferred in-drain retries) → corrected by theNO_PROGRESSclassification; adversarial round 2 traced all 13 result sites and every repeat class to bounded termination, zero findings; architectural pass approved the drain-loop ownership seam.Found while reviewing band-agent's merged-turn work (ack path shared with
ExecutionContext); no behavioral coupling to it.