fix(channels): close residual ~50ms cli elicitation acquisition window with ack handshake#6430
Merged
Merged
Conversation
…w with ack handshake ElicitGuard::acquire() previously set the yield_requested flag and returned immediately, relying on run_tty_reader's next 50ms poll cycle to actually stop touching stdin. Add a generation-tagged ack Notify: the reader bumps a parked_generation counter and fires ack only after it has genuinely parked, and acquire() waits for a generation newer than the one it captured at entry, rejecting any stale/leftover permit from a previous timed-out acquisition. The guard is now constructed before the ack-wait await so cancellation always runs Drop and clears the flag. Closes #6404
bug-ops
enabled auto-merge (squash)
July 17, 2026 23:09
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
CliChannel::elicit()/confirm()acquired anElicitGuardthat set ayield_requestedflag to pause the backgroundrun_tty_readertask, but returned immediately without confirming the reader had actually parked — leaving a bounded ~50ms window (bounded by the reader'sevent::pollcycle) where both readers could race for the same keystroke on stdin. This was an accepted MVP tradeoff from PR fix(channels): coordinate elicit()/confirm() readline with the background stdin reader #6403 / issue CLI elicitation readline races with background chat-input reader on stdin, causing client-side timeout #6398.ElicitGuard::acquire()now awaits a generation-tagged ackNotify:run_tty_readerbumps aparked_generationcounter immediately before firing the ack, andacquire()only proceeds once it observes a generation newer than the one captured at entry — closing the window instead of assuming it has elapsed, and correctly rejecting a stale/leftover permit from a previous timed-out acquisition. Bounded by a 200ms timeout so a reader that was never spawned or has already exited cannot hang the caller forever.acquire()at any point always runsDropand clears the flag.Test plan
cargo +nightly fmt --check— cleancargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings— cleancargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins -E 'package(zeph-channels)'— 287/287 passedRUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links") — cleanCloses #6404