Repository navigation
Only show the call prompt for real browser calls, and remember Not now - #1800
Merged
Merged
Conversation
…t now WIP: browser mic needs a call tab title, or 20s with audio/camera, or 60s; known non-call sites (ChatGPT, Loom) never prompt; Not now escalates and persists per kind of call; suppressions send one event instead of two. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FW21bnupYQgxzJewPJgDup
…etector gating Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FW21bnupYQgxzJewPJgDup
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FW21bnupYQgxzJewPJgDup
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FW21bnupYQgxzJewPJgDup
Only titles that exist during a call count from any window; chat apps, call sites and the Meet home page only count while focused, and mail or calendar titles are skipped. A focused non-call site sticks for the browser session, so ChatGPT voice stays quiet after a tab switch. Window titles are read off the main actor under a 0.3 s budget. Learning: learned-off only applies when titles are readable, the camera and call sites get their own kinds that only back off, a Not now to any browser prompt covers the rest of that call (capped at 8 h), manual recordings only credit kinds the call raised, old recordings age out, and turning detection off and on resets it. Call-site prompts get their own id and never quiet a whole provider. Also: 30 s grace when a browser lets go of the mic, the camera wait starts when that browser comes to the front, title re-reads stop once a prompt is decided, the funnel keeps prompted or recorded sessions, the nudge skips learned-quiet calls, tab-named calls report their provider, not_a_call carries non_call_site evidence, and the Accessibility summary mentions spotting browser calls. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FW21bnupYQgxzJewPJgDup
…nded
A Meet tab named after a calendar topic ("Meet - Q3 calendar planning")
was skipped by the mail and calendar filter and fell back to the generic
prompt; Meet's own title patterns now run first. meeting_detected_call_ended
now carries app_signal (browser_mic, native_output...) so the funnel can
split browser calls from native ones. Notes that Teams in-call prefixes
are English only.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FW21bnupYQgxzJewPJgDup
- Present nothing while a browser session's first title read is still running, so a calendar prompt cannot win over the actual call (fixes the generic-browser-vs-calendar test that the async read broke). - Keep a browser Not now through the 30 s mic-release grace, so a muted Safari call is not re-asked on unmute. - Call apps are checked before non-call words, markers match whole words, and a non-call site only sticks when it was in front within 10 s of the browser taking the mic. - Mail and calendar titles only count for a leading Meet code; mail detection matches the app's own title part so "Meet - Q3 calendar planning" still counts; the Zoom rule no longer matches Zoom help pages. - Compare browser families as app families (WebKit is Safari). - stop() ends the browser session instead of leaving a cancelled read. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FW21bnupYQgxzJewPJgDup
CI's fast-test compile timed out type-checking an untyped literal array of chained multiplications inside assertEqual. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FW21bnupYQgxzJewPJgDup
The app-reminder, call-detected and missed-call prompts hardcoded "Option-M" even after the shortcut was rebound, and the missed-call nudge said "Tap Record" on a Mac. They now show the current binding the way the menu bar does (for example ⌥M) and say Click. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FW21bnupYQgxzJewPJgDup
claude Bot
pushed a commit
that referenced
this pull request
Sep 24, 2026
… audio Sources/Meeting/CLAUDE.md: take #1800's MicActivityMonitor entry and keep the note that the one-shot currentMicInputBundleIDs (Boost Mic) runs on a detached task. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgXMcLRGBtiSiybdgyD1VJ
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.
Requested by Justin · project thread
Before: any browser that held the mic for 3 seconds got a "Call detected in your browser" prompt. ChatGPT voice, web dictation, a mic test page: all of them. "Not now" lasted 30 minutes and was forgotten on relaunch, so the same person got asked again and again.
After: a browser window whose title only exists during a call (a Meet tab, the Zoom web client, a Teams meeting) prompts right away with the right name. A focused voice assistant or recorder (ChatGPT, Claude, Loom...) doesn't prompt for that session, even after a tab switch. A focused call app that isn't clearly in a call (Teams chat, a Slack huddle, the Meet home page) waits 20 seconds. Anything else waits 60 seconds of steady mic use (20 if the browser is also playing audio or the camera is on) and then asks once. Each Not now keeps it quiet longer (30 min, 2 h, 8 h, then a day for unknown sites), a recording resets it, it survives a relaunch, and turning auto call detection off and on clears it. The prompts also show the user's own meeting shortcut instead of always saying Option-M.
How: the app reads the browser's window titles through the Accessibility access it already has for paste-back, on a background queue under a 0.3 s budget. Titles are never logged, stored or sent. No new permissions. Not now is remembered per kind of prompt (unknown browser use, call site, camera, named browser call, each native app), so turning down ChatGPT voice never hides a real Meet. It also stops sending the same suppression twice to analytics (about 33k duplicate events a month).
Why
Pain point #4 in the customer list: the "call detected" prompt pops up every time a browser uses the mic. Over 30 days (CI builds excluded) browser prompts got 2.4 Not nows for every recording, vs 1.3 for native apps. Half of all Not nows came from people who had already said Not now 3 times in a row.
Product Impact
meetingsmeeting reliabilityWhat changed
Sources/Meeting/BrowserCallEvidence.swift(new): title rules (call-only titles from any window, Meet's checked before the mail and calendar filter; call sites and non-call sites only from the focused window; mail and calendar skipped otherwise) and the prompt / wait / not-a-call decision.Sources/Meeting/MeetingPromptLearnedBackoff.swift(new): remembered Not now streaks per kind, saved in UserDefaults, with a reset.Sources/Meeting/BrowserWindowTitleReader.swift(new): background Accessibility title reader with an overall time budget; returns nothing when Accessibility is off.MeetingPromptDetector: browser mic goes through the evidence check with sticky call / not-a-call verdicts, a 30 s grace when the mic drops, re-reads that stop once decided, new suppression reasons (awaiting_call_evidence,not_a_call,declined_this_call,learned_quiet), and a 15 min suppression telemetry cooldown instead of 90 s. Learned-off only applies when titles are readable.MicActivityMonitor: reports when the browser that holds the mic is also playing audio.TranscriptedApp: stops the duplicatemeeting_prompt_outcome_recorded(suppressed)event, wires the new output signal, and resets the learning when auto call detection is turned back on.call_evidence;meeting_detected_call_endedcarriesapp_signal(browser vs native) and the tab-named provider. Both allowlisted.BrowserCallEvidenceTests,MeetingPromptLearnedBackoffTests; detector, heuristics, monitor, telemetry and analytics-policy tests updated, including ChatGPT voice after a tab switch, chat apps in the background, a Not now covering the rest of the call, no learned-off without titles, manual recordings, and a rebound meeting shortcut.Sources/Meeting/CLAUDE.md,docs/auto-call-detection-spec.md(Phase 5).Expected change (PostHog replay of the new backoff over 56 devices' real browser prompt history): about 41% fewer browser Not nows from the backoff alone, at the cost of 12 of 142 browser prompt recordings (8.5%, on 5 devices; 9 of those 12 were on devices that also start meetings by hand). The title and wait rules come on top and can't be replayed from telemetry: up to 328 browser prompts a month were for mic sessions under a minute, which the wait removes.
How I checked it
scripts/dev/agent-preflight.shpython3 scripts/dev/check-build-source-lists.py,python3 scripts/dev/check-analytics-emitters.py,bash -n scripts/entrypoints/run-tests.shbash build.sh --no-open(CI app-build green on 99e6706; no Swift toolchain in the session)bash run-tests.sh(CI checks green on 99e6706)bash run-integration-smoke.sh/ spm-tests (CI, running on the latest head)Risk Review
call_evidenceandapp_signalare fixed enums. No new permissions.meeting-prompt-learned-backoff-v1.meeting_prompt_outcome_recordedsuppressions or suppression events should be annotated on release..agent-review/visuals/evidence (no layout changes; prompt text and one permission summary line changed)Notes
CapturePillControlleror theonPromptRequestwiring that Show a "Mic only" note when a meeting records just the mic #1794 changes.🤖 Generated with Claude Code
https://claude.ai/code/session_01FW21bnupYQgxzJewPJgDup