Skip to content

Right Option dictation starts on key press, not on release - #1858

Merged
r3dbars merged 2 commits into
mainfrom
claude/transcription-speed-percentiles-yyabey
Sep 25, 2026
Merged

r3dbars merged 2 commits into
mainfrom
claude/transcription-speed-percentiles-yyabey

Conversation

@r3dbars

@r3dbars r3dbars commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Requested by Justin · project thread

Why

Before: a right Option tap (the default hands-free key) only counts when you let go of it, because Option+M (meeting) and Option+Shift+V (paste last) also use Option. So every hands-free start quietly adds however long the key is held, about 0.1 to 0.2 s, and none of the logged start timings include it. On Justin's Mac, 289 of about 294 recent dictations were this tap.

After: the tap counts the moment the key goes down, so dictation (and the start click from #1857) begins that much sooner. If another key goes down while right Option is still held (Option+M, or typing é with Option+E), the dictation that press started is dropped quietly and the combo works as before.

Waiting on Justin's pick on the decision card in the thread. Don't merge until he chooses "Start on press".

Product Impact

  • Affects: dictation
  • Lane: dictation reliability
  • Why this matters: Justin wants dictation to start "insanely fast". Waiting for the key release is the largest start delay left that isn't macOS itself.

What changed

  • PhysicalShortcutMatcher.firesSharedModifierOnPress(secondsSinceLastTypedKey:): a hands-free modifier that other shortcuts share fires on press, unless a key was typed in the last second. Mid-typing, right Option is more likely the start of a combo, so it keeps waiting for release there.
  • ContextCaptureEngine detector: it records when a key was last typed. When the shared hands-free modifier fires on press, it remembers the key until release. Any key that goes down while it's still physically held sends a new .comboInterrupted phase. A missed release (tap disabled) or resetState clears it.
  • ContextCaptureEngine routing: it remembers the session a hands-free press started. On .comboInterrupted it calls the new DictationSessionController.abandonDictationStartForModifierCombo(sessionID:), which cancels that exact session with no sound, no error overlay, and no saved audio, and writes a local dictation_start_dropped_for_modifier_combo log line. A press that stopped a dictation is left alone.
  • Push-to-talk (Fn) and keyed shortcuts are unchanged. If no other shortcut shares the hands-free key, it already fired on press and still does.
  • Sources/Capture/CLAUDE.md documents the behavior and adds a manual check.

How I checked it

  • scripts/dev/agent-preflight.sh
  • bash scripts/dev/linux-checks.sh (runs without Swift): 48 passed, 0 failed
  • Selected checks from .agents/test-matrix.yml for the files changed (source pins)
  • bash build.sh --no-open (CI)
  • bash run-tests.sh (CI). New suite in Tests/PhysicalShortcutMatcherTests.swift
  • Performance budget passed
  • bash run-integration-smoke.sh: not needed, no Sources/Meeting/ or Core changes
  • swift test: not needed
  • bash run-e2e-smoke.sh: not mapped
  • Manual check: pending, needs a Mac with a keyboard

Checks I could not run, and why:

  • No Swift toolchain in the cloud session, so CI is the first build.
  • The event-tap behavior needs a real keyboard on a Mac.

Mac or hardware test still needed? Yes:

  1. Tap right Option after not typing for a second. Dictation starts on key down, and events.jsonl shows dictation_start_requested close to the physical press. On main it only starts after release.
  2. Hold right Option and press M. A meeting starts, and no dictation is left running. The log shows dictation_start_dropped_for_modifier_combo. On main no dictation starts at all.
  3. While typing, press right Option+E then E, which gives é. No dictation starts, same as main.
  4. Right Option+Shift+V pastes the last dictation, and no dictation is left running.
  5. Tap right Option again while dictating. It stops and pastes, now on key down.

Risk Review

  • Privacy / local-first behavior reviewed: the mic still opens only on a real press. A combo press may open it for a moment before it's dropped.
  • New analytics properties or Sentry tags: none. The new event is local-only (.info).
  • Checked the text-pin tests for every file I edited (check-source-pins.py --changed-only: pass; read the ContextCaptureEngine.swift pins in ContextCaptureEnginePolicyTests, DictationQueuedStartPolicyTests, DictationRecordingStartOverlayPolicyTests)
  • Storage path or migration impact reviewed: none
  • Public-facing copy: none
  • Release/update impact reviewed: none
  • Agent PRs got an independent deep review of the full diff
  • UI changes: none
  • No private transcripts, audio, tokens, personal paths, or customer data are included

Notes

  • Known tradeoff: a right Option combo made after a pause (for example Option+M to start a meeting) now gives the start click and a brief overlay before the dictation is dropped. Typing combos like é mid-sentence keep today's wait.
  • A dropped combo start has already counted in dictation_start_requested but sends no terminal PostHog event, so it shows up as an attempt without an outcome. That's acceptable at the expected rate. If it's noisy, a follow-up can add a failure_kind.
  • Builds on Dictation start: pinned recorder for built-in and wired mics, faster launch warmup #1857's start-click change but doesn't depend on it.

Agent handoff

COORD_DONE: BRIEF | this PR | right Option hands-free fires on press, quiet drop on combo | none | Justin's pick on the card, then CI + deep review + Mac check | linux-checks, source pins | wait for his pick

🤖 Generated with Claude Code

https://claude.ai/code/session_016DYGa1i8HDv497ewpWgaCM


Generated by Claude Code

Hands-free on right Option waited for the key to come back up whenever
another shortcut also used Option (the defaults do: Option+M and
Option+Shift+V), so every start silently added the whole hold, about
0.1 to 0.2 s. Almost all real starts are this tap.

It now fires on press unless a key was typed in the last second, where a
right Option press is more likely a combo like Option+E for é. If another
key goes down while it is still held, the detector reports
comboInterrupted and the dictation that press started is dropped with no
sound, error, or saved audio, and the combo runs as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016DYGa1i8HDv497ewpWgaCM
Review fixes:
- A right Option press during a dictation stops and pastes it, which a
  following combo key can't undo (Option+Shift+V pasted twice, Option+M
  cut the take). Those presses wait for release again; only a start fires
  on press. The engine mirrors isDictating into the detector.
- A dropped combo start now sends dictation_start_dropped_for_modifier_combo
  (duration_bucket, trigger), so the start funnel doesn't read it as a
  lost start. Allowlisted and listed in the privacy doc.
- A combo on a press that only queued a start behind a finishing take
  drops the queued start.
- Moved the orphaned cancelDictation doc comment back.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016DYGa1i8HDv497ewpWgaCM
@r3dbars
r3dbars marked this pull request as ready for review September 25, 2026 16:53
@r3dbars
r3dbars merged commit 8c99583 into main Sep 25, 2026
8 checks passed
@r3dbars
r3dbars deleted the claude/transcription-speed-percentiles-yyabey branch September 25, 2026 16:53
r3dbars pushed a commit that referenced this pull request Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants