Repository navigation
PTY delivery: clear blank-composer residue holding failed-draft latch; dead-letter deliveries stuck behind blocked_on_send - #1984
Draft
khaliqgant wants to merge 1 commit into
Draft
khaliqgant wants to merge 1 commit into
khaliqgant wants to merge 1 commit into
Conversation
Live on sf-mini/finn-mini (2026-10-19) desktop-upgrade-sf/finn held 3 and 9 deliveries for 42-56h (~675 resends, failed_attempts always 0, surfaced_and_acked=0) behind a failed_composer_latch that never released. - Recognise Claude's prompt row `❯` + U+00A0 as a composer anchor; the ASCII-only match left composer_is_idle false on an empty composer. - Erase blank-row residue (line breaks from the failed body) under a bare prompt with one backspace per row, bounded to 3 spaced tries and only when no text exists anywhere in the composer. - retry_pending_delivery: a handoff to a worker in BlockedOnSend no longer resets failed_attempts, so MAX_DELIVERY_RETRIES dead-letters it visibly. Working workers keep the old behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Member
Author
|
CI note on the The workflow has been re-run 5 times on 16a9260 and failed a different shard almost every time. I checked whether this PR causes any of them:
Conclusion: these are existing Relaycast-dependent flakes, not regressions from this PR. All Rust and unit checks pass. 🤖 Generated with Claude Code |
This branch has not been deployed
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.
Incident (2026-10-19)
Two broker PTY workers had relay messages stuck for days.
desktop-upgrade-sf(sf-mini) held 3 deliveries anddesktop-upgrade-finn(finn-mini) held 9, for 42-56h, while each Claude sat idle at an empty prompt./api/statusshowed about 511-675 resends per delivery, withfailed_attemptsalways 0 and nolast_error./api/node-deliveryshowedsurfaced_and_acked: 0since spawn, and the worker state wasblocked_on_send.POST /api/spawned/<name>/flush) did nothing (flushed 0, held 0).[22,3]on a blank row directly under the prompt row❯.Root cause
❯+ U+00A0.composer_candidates(broker/delivery_verification.rsis_prompt) only accepted❯or❯with an ASCII space. As a resultcurrent_composerreturnedNoneandcomposer_is_idlewas false, even for a truly empty composer.failed_draft_released(pty_worker.rslatch release, ~3113) could therefore never succeed.WAIT_DELIVERY_ACK_TIMEOUT) the broker re-sent each held delivery. The worker dropped it as a "duplicate pending delivery" (pty_worker.rs~1557). Because the handoff succeeded,retry_pending_delivery(runtime/delivery.rs) resetfailed_attemptsto 0. Nothing ever dead-lettered.Fix
is_prompttreats U+00A0 as a space.blank_composer_residue_rows/blank_composer_residue_cleanup. While a failed-draft latch is held and the composer is a bare prompt followed by only blank rows (at most 4, closed by the composer frame rule, nothing at or after the cursor), the worker sends one backspace (0x7f) per blank row. This is bounded toMAX_RESIDUE_CLEANUPS = 3tries, spaced 2s apart. It never fires when any text exists in the composer, so a human draft is never erased.retry_pending_delivery: a successful handoff to a worker whose state isBlockedOnSendno longer resetsfailed_attempts. It increments the count and setslast_error = "worker blocked_on_send; delivery not injected", soMAX_DELIVERY_RETRIESdead-letters the delivery after about 10 resends.Workingworkers keep the old behaviour, so a long turn never dead-letters wait-mode messages.failed_draft_latchedescalation fires. The latched delivery was already reported failed when it was latched, and the broker budget above then dead-letters the queued ones.Tests
blank_composer_residue_holds_the_failed_draft_latch_until_cleared: the real 24-row screen from the sf broker. With the residue it is not idle, residue = 1 row, cleanup =[0x7f]. Once cleared it is idle and the latch releases, which also covers the U+00A0 prompt.blank_composer_residue_never_matches_a_composer_holding_text: text on the cursor row, text on the prompt row, and text after the cursor all returnNone.residue_cleanup_is_bounded_and_spaced.resend_to_blocked_on_send_worker_counts_against_retry_budget_and_dead_lettersandresend_to_working_worker_still_resets_failed_attempts.cargo fmtis clean.clippy -D warningson toolchain 1.97 fails only on two pre-existing lints innode_control.rs(large_enum_variant, result_large_err), which this PR does not touch.Open finding (not fixed here)
When the residue was cleared live by hand (
POST /api/input/<name>with one\x7f), the latch released, and then every queued delivery (3 on sf, 9 on finn) failed withprompt_unproven. A fresh message afterwards worked.prompt_wait_startedis set when the injection is popped (pty_worker.rs~2327), andprompt_unprovenhas a single source (pty_worker.rs~2413) that measures from it./api/inputwrite raised the human-ownership / interactive-hold state while queued injections were popped. The window then elapsed while the hold-gated delay arm could not run.auto_suggestion_visiblesent Escape into Claude's empty composer, moving the cursor off the prompt row.RUST_LOG=agent_relay::worker::pty=debug.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Agent Relay sessions
claudesessiona6d60c2d· opened viagh pr create· last active 2026-10-20