Repository navigation
fix(relay): retry live states that can recover - #1633
Merged
Merged
Conversation
This was referenced Oct 26, 2026
loganj
marked this pull request as ready for review
October 26, 2026 15:50
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
loganj
force-pushed
the
fix/live-terminal-retry
branch
from
October 26, 2026 19:41
faef9f0 to
a6e2461
Compare
Several live-connection failures were final until the app restarted, so an agent in the app could silently stop hearing mentions. - Drop a single undecodable EVENT instead of failing its whole route. - Retry a rejected live AUTH or a failed live signature on a slow timer (60 s doubling to 10 min). The error stays in state and session recovery still treats it as settled, so it cannot shorten the wait. A signer that does not match the viewer stays terminal. - Retry routes CLOSED with a needs-action reason (blocked:, auth-required:, unknown text) on the recover tick with the same backoff. The "not a channel member" denial flow is unchanged. - Keep the recover tick running when callbacks.recover throws, and log it. - Broker SSE client: reset the reconnect backoff once a stream delivers, and retry 400/401/403/413 stream rejections slowly instead of stopping. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
…retries Every accepted broker stream sends its state at once, so resetting the reconnect backoff on the first frame let a stream that drops right after opening retry every 500 ms forever. Reset it only after a stream stayed up for a minute, as the WebSocket path does. A slow automatic retry can remove the "Retry live updates" button while it has focus. Track focus for that control as for the session recovery notice, and hand focus on when it goes away. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
loganj
force-pushed
the
fix/live-terminal-retry
branch
from
October 27, 2026 15:36
a6e2461 to
065239d
Compare
…deadline A refused live route gets a recover-tick deadline. Manual Retry or a scope replacement moved it back to pending with that deadline intact, so a later unsupported cooldown that stopped the queue was revived by the recover tick. Route both queue stops through one helper that clears the deadline and keeps the refusal count. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
Design review: while the live layer quietly retries a refused connection or route, the "Live updates limited" notice lost its Retry button, or vanished and came back, on every attempt. Hold the notice, its reason and its Retry while an attempt runs; the hold ends once the attempt succeeds or a new failure replaces it. Retry now leaves the notice and its focused button in place, and focus moves on only when the notice goes away. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
Review: the hold counted only a reconnect or a pending route as an attempt. The minute recovery tick also refreshes the roster, and a head can refresh too; either made live state busy, so the hold ended, the focused Retry unmounted and came back unfocused. Hold until liveRecoveryStatus settles instead: either the failure returns or it has cleared. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
kalvinnchau
reviewed
Oct 27, 2026
Review: liveRecoveryStatus covers the whole session, so another channel's pending route or head, a transient error elsewhere or a previews check kept this channel's old notice and Retry after it was live again, and focus never moved on. Hold only while this channel still has an issue or work in flight: connection setup, the roster read, its own head read or a relevant route. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
Review: the hold kept Retry for any displayed issue, so a channel that recovered to a partial roster or capacity notice kept Retry while unrelated work elsewhere was unsettled. Hold only for a blocking issue or this channel's own work in flight. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
Review: issue and blocking repeated the same clauses, so a new actionable state had to be added to both. issue is now blocking plus the two passive notices (a capacity-limited route, a partial roster). No behavior change. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
kalvinnchau
approved these changes
Oct 27, 2026
kalvinnchau
left a comment
Contributor
There was a problem hiding this comment.
🤖 Approved. No actionable findings at 647c1fc. The duplicate status predicate is resolved, and Retry focus, passive notices, and channel-local recovery remain covered. Merge remains contingent on required CI passing.
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.
🤖
Summary
blocked:orauth-required:). Before: final. Now: retried on the existing one-minute recovery timer with the same backoff. The "not a channel member" denial flow is unchanged.Details
liveSlowRetryDelay(src/features/relay/live.ts), serves the auth, route and broker cases. It starts at 60 s, the existing recovery tick, so a refusal is never retried faster than today's timer. It is capped at 10 minutes, so a relay that keeps refusing sees at most 6 attempts an hour per route.docs/relay-queries.mdis updated where it described these states as terminal.Not in this PR
/streamretry alone does not register again, so that case still needs something to call registration again.🤖 Generated with Claude Code