Skip to content

fix(dialog): raise permission-guard quiet period to survive natural typing pauses - #3393

Merged
taciturnaxolotl merged 3 commits into
charmbracelet:mainfrom
albatrossflyon-coder:fix/permission-guard-typing-ceiling
Aug 2, 2026
Merged

taciturnaxolotl merged 3 commits into
charmbracelet:mainfrom
albatrossflyon-coder:fix/permission-guard-typing-ceiling

Conversation

@albatrossflyon-coder

Copy link
Copy Markdown
Contributor

Fixes #3383.

The bug

#3055 added a grace period so an in-flight keystroke can't act on a permission dialog before the user sees it: Overlay.Update absorbs keystrokes until graceQuietPeriod (200ms) of silence, up to a graceMaxDelay (1.5s) ceiling.

That correctly handles a single stray keystroke or a fast burst. It doesn't handle the case in #3383: a user composing their next message while a permission dialog is open from a prior tool call. Ordinary typing has natural pauses between words/thoughts that regularly exceed 200ms — nothing like a stuck key or auto-repeat — so the dialog arms mid-sentence, and the very next character the user types lands on the permission dialog instead of the editor.

Root cause, traced

  • internal/ui/model/ui.go's handleKeyPressMsg routes all keys to m.handleDialogMsg → Overlay.Update whenever a dialog is open, which is the correct path (no separate leak point).
  • Overlay.inGracePeriod() (internal/ui/dialog/dialog.go) arms as soon as graceQuietPeriod elapses since the last absorbed key — 200ms, shorter than a typical inter-word pause.
  • The original PR's own description says the grace period should let "a sustained burst of fast typing [be] fully absorbed," but a paused sentence isn't a burst — it's exactly the case that falls through.

Fix

Raised graceQuietPeriod from 200ms to 700ms — comfortably past an ordinary composing pause, while still arming quickly once the user genuinely stops typing. Left graceMaxDelay (1.5s) untouched; it's a separate, already-tested safety net for a truly stuck key.

The exact number is a judgment call — happy to tune it if you have a preference or telemetry on real typing cadences.

Testing

Added TestOverlay_NaturalTypingPauseArmsMidSentence, which reproduces the bug deterministically (no live terminal needed, unlike #3373): types a few characters, backdates a 400ms pause (a normal thinking-pause, well under the old 200ms and comfortably under the new 700ms), then resumes typing. Confirmed red against current main (the resumed keystroke reaches the dialog), green after the fix.

  • go test ./internal/ui/dialog/... — 32 passed
  • go test ./internal/ui/... — 722 passed
  • go build ./... — clean

…yping pauses

Fixes charmbracelet#3383.

graceQuietPeriod (200ms) armed the permission dialog's keystroke guard
after any pause shorter than a normal mid-sentence thinking pause, so a
user composing their next message while a permission dialog was open
would have a keystroke land on the dialog instead of the editor as soon
as they paused between words. Raised to 700ms, comfortably clear of
ordinary typing pauses while still arming promptly once the user
actually stops typing.

Added a regression test (TestOverlay_NaturalTypingPauseArmsMidSentence)
that reproduces the exact race deterministically without needing a live
terminal: a 400ms pause mid-sentence used to leak the next keystroke to
the dialog; it no longer does.
@taciturnaxolotl

Copy link
Copy Markdown
Member

halo! just tested with some typing data from myself. I think somewhere around 400-450 ms would be the sweet spot. We aren't really looking to account for pauses / rereading in this just preventing the period of time where the hands are still typing something but the brain hasn't reacted to the popup yet.

@taciturnaxolotl

Copy link
Copy Markdown
Member

i think the test and comment could be removed as well

Per taciturnaxolotl's review: 400-450ms is the sweet spot -- we're only
covering the window where hands are still mid-keystroke but the brain
hasn't reacted to the dialog yet, not accounting for a genuine pause to
think or reread. Split the difference at 425ms.

Also removed TestOverlay_NaturalTypingPauseArmsMidSentence and its
comment as requested -- the existing grace-period tests already cover
the mechanism this test was duplicating.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@albatrossflyon-coder

Copy link
Copy Markdown
Contributor Author

Thanks for testing this against real typing data! Pushed both changes:

  • graceQuietPeriod tuned to 425ms (splitting your 400-450ms range)
  • Removed TestOverlay_NaturalTypingPauseArmsMidSentence and its comment

go test ./internal/ui/dialog/... — 31 passed, go test ./internal/ui/... — 721 passed, go build ./... clean.

Ready for another look whenever you have a chance.

@taciturnaxolotl

Copy link
Copy Markdown
Member

can you revert the comment change too?

taciturnaxolotl asked to drop the comment change too, not just the test.
@albatrossflyon-coder

Copy link
Copy Markdown
Contributor Author

Reverted the comment back to the original one-liner, keeping graceQuietPeriod at 425ms. Pushed.

go build ./... clean.

@taciturnaxolotl
taciturnaxolotl enabled auto-merge (squash) August 2, 2026 21:35
@taciturnaxolotl
taciturnaxolotl enabled auto-merge (squash) August 2, 2026 21:36
@taciturnaxolotl
taciturnaxolotl merged commit 1134a5d into charmbracelet:main Aug 2, 2026
15 checks passed
Alsan pushed a commit to Alsan/crush that referenced this pull request Aug 5, 2026
XBoy-352 pushed a commit to XBoy-352/crush that referenced this pull request Aug 8, 2026
hirochimi pushed a commit to hirochimi/crush-study that referenced this pull request Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The "writing while permission modal appears" guard does not work

2 participants