Skip to content

fix(channels): close residual ~50ms cli elicitation acquisition window with ack handshake#6430

Merged
bug-ops merged 1 commit into
mainfrom
feat/issue-6404/cli-elicitation-ack-handshake
Jul 17, 2026
Merged

fix(channels): close residual ~50ms cli elicitation acquisition window with ack handshake#6430
bug-ops merged 1 commit into
mainfrom
feat/issue-6404/cli-elicitation-ack-handshake

Conversation

@bug-ops

@bug-ops bug-ops commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • CliChannel::elicit()/confirm() acquired an ElicitGuard that set a yield_requested flag to pause the background run_tty_reader task, but returned immediately without confirming the reader had actually parked — leaving a bounded ~50ms window (bounded by the reader's event::poll cycle) 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 ack Notify: run_tty_reader bumps a parked_generation counter immediately before firing the ack, and acquire() 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.
  • The guard is constructed before the ack-wait await, so cancellation of acquire() at any point always runs Drop and clears the flag.

Test plan

  • cargo +nightly fmt --check — clean
  • cargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings — clean
  • cargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins -E 'package(zeph-channels)' — 287/287 passed
  • Rustdoc gate (RUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links") — clean
  • 4 new regression tests covering the ack-handshake happy path, no-reader timeout fallback, stale-permit rejection, and cancellation-mid-await flag clearing

Closes #6404

…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
bug-ops enabled auto-merge (squash) July 17, 2026 23:09
@github-actions github-actions Bot added documentation Improvements or additions to documentation channels zeph-channels crate (Telegram) rust Rust code changes bug Something isn't working size/L Large PR (201-500 lines) labels Jul 17, 2026
@bug-ops
bug-ops merged commit f2d1517 into main Jul 17, 2026
43 checks passed
@bug-ops
bug-ops deleted the feat/issue-6404/cli-elicitation-ack-handshake branch July 17, 2026 23:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working channels zeph-channels crate (Telegram) documentation Improvements or additions to documentation rust Rust code changes size/L Large PR (201-500 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cli elicitation stdin coordination: close the residual ~50ms acquisition window with an ack-handshake

1 participant