Polish Huddle voice controls - #4694
Conversation
Signed-off-by: kenny lopez <klopez4212@gmail.com>
|
🤖 Huddle UI snapshots Drawer and agent voice controlsThe drawer keeps its surface behind the rounded app and exposes agent controls from the avatar. Interrupt agent speechA responding agent replaces its name with a visible Stop control without changing tile height. Add an agentThe picker uses the shared modal styling and starts a stopped agent when selected. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d7192503c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
wesbillman
left a comment
There was a problem hiding this comment.
Requesting changes on Wes's behalf. I found three user-visible correctness issues in the new Huddle controls: the displayed mute action can leave the microphone open after PTT release, a stale Stop click can discard the next agent utterance, and removing an agent can leave that agent's current/queued speech playing. Details and requested regression coverage are inline. I am acting on Wes's behalf and am not approving this PR.
Signed-off-by: kenny lopez <klopez4212@gmail.com>
…p-speaking Signed-off-by: kenny lopez <klopez4212@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 53d4e079a1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: kenny lopez <klopez4212@gmail.com>
…p-speaking Signed-off-by: kenny lopez <klopez4212@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1015ade24e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: kenny lopez <klopez4212@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 80258a5066
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: kenny lopez <klopez4212@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6e9fbbd176
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: kenny lopez <klopez4212@gmail.com>
wesbillman
left a comment
There was a problem hiding this comment.
Carl here, commenting on Wes's behalf. Requesting changes at exact head 05c7623b1debc8619fd9d1dcf29677e59bc76d01.
P1 — a stale Stop click can discard the same agent's next queued utterance after the displayed utterance has already drained. active_speaker and tts_active remain set until the worker notices player.empty() during receive-timeout or pre-synthesis cleanup (desktop/src-tauri/src/huddle/tts.rs:557-575, 662-677). During that real drain→cleanup window, the UI still presents Alice's Stop action. Clicking it passes request_active_speaker_cancel's ownership check and advances Alice's generation (desktop/src-tauri/src/huddle/tts_voice_transition.rs:133-157), invalidating Alice text already queued under the prior generation (desktop/src-tauri/src/huddle/tts.rs:603-608) even though the utterance the user intended to stop is over.
The new regression does not cover this ordering because it manually clears active_speaker before issuing the stale click (tts_voice_transition.rs:463-475). Please bind Stop to actual player/utterance liveness under the same synchronization and add a regression where playback is empty but ownership cleanup has not run; Alice's already-queued next utterance must survive.
The earlier mute/PTT, agent-removal, unrelated-speaker, provider-start, and wrong-speaker Stop issues appear fixed.
Signed-off-by: kenny lopez <klopez4212@gmail.com>
…p-speaking Signed-off-by: kenny lopez <klopez4212@gmail.com>
|
🤖 Addressed Wes’s P1 in 0aa4cbb. Stop now reads the actual Rodio player under the same player-operation lock used for append and clear, and only advances the selected agent’s generation when playback is still non-empty and that agent still owns it. Added a device-free regression with an empty player, stale Alice ownership, and Alice’s already-queued next utterance; the Stop request is rejected and the queued utterance remains current. All 66 Huddle TTS tests, strict Clippy, 4,177 desktop tests, the native workspace suite, and the full merged-tree pre-push gate pass. Latest main is merged at 241d57f. |
wesbillman
left a comment
There was a problem hiding this comment.
I’m commenting on Wes Billman’s behalf as his review agent.
P1 — Do not treat every empty player as a stale Stop click.
request_active_speaker_cancel now rejects Stop whenever player.empty() is true (desktop/src-tauri/src/huddle/tts_voice_transition.rs:178-188). That closes the drain→cleanup case, but empty() is also transiently true when playback has exhausted one synthesized chunk while the worker is still synthesizing a later chunk of the same utterance. tts_active and active_speaker deliberately remain set across that lookahead pipeline (tts.rs:451-524, 722-856), so the UI still presents that speaker as active. If the user clicks Stop during such a synthesis gap, this function returns false without advancing the speaker generation or installing speaker_cancel; the in-flight synthesis then passes the unchanged generation check in append_audio and appends more audio, so the agent resumes speaking after Stop.
The fix needs to distinguish “utterance fully drained with only stale ownership/UI state” from “player temporarily empty while the owned utterance still has synthesis in flight.” Please add a regression for the latter alongside the new drained-playback regression: empty player + active/in-flight Alice utterance must accept Stop and prevent Alice’s later synthesized chunk from appending, while empty player + fully drained Alice state must preserve already-queued next speech.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 241d57ffc4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if !agent_is_present { | ||
| eprintln!( | ||
| "buzz-desktop: tts stage=queue status=dropped reason=speaker_removed route_id={route_id}" | ||
| ); | ||
| return Ok(()); |
There was a problem hiding this comment.
Avoid dropping relay-verified newly added agents
When an agent is added to the huddle by another participant, the React TTS subscription can authorize that speaker from the relay via get_huddle_agent_pubkeys, but this new native gate still checks only the local hs.agent_pubkeys snapshot, which is refreshed separately by check_pipeline_hotstart on a 15s throttle. In that window, the first responses from the newly added agent are accepted by the frontend and then silently returned here as speaker_removed, so remote agent additions can miss their initial spoken replies until the backend refresh catches up.
Useful? React with 👍 / 👎.
Track synthesis-in-flight separately from player queue liveness so Stop still cancels an utterance while its player is temporarily empty. Keep repeat clicks idempotent while cancellation is pending and serialize the drain boundary with player operations. Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> Signed-off-by: Wes <wesbillman@users.noreply.github.com>
The terminal z-index is local to the app surface and cannot be compared against the sibling drawer backdrop. Assert the two relevant stacking contexts instead so the test remains valid with the docked terminal. Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> Signed-off-by: Wes <wesbillman@users.noreply.github.com>
…links * origin/main: fix(desktop): integer-align custom reaction emoji (#4779) Polish Huddle voice controls (#4694) fix(local-archive): default both archive settings to enabled (#4750) fix(mobile): stop oversized read-state retry loop (#4595) Signed-off-by: npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
* commit 'ce3cf3cd2': (76 commits) Polish Huddle voice controls (#4694) fix(local-archive): default both archive settings to enabled (#4750) fix(mobile): stop oversized read-state retry loop (#4595) fix(desktop): close reconnect gaps that previously required CMD+R (#4737) Dock Buzz Term within channel workspace (#4724) perf(relay): index channel-id lookups and skip trace-only reads (#4647) fix(agents): canonicalize stale persona harness pins (#4631) Refine community invite links (#4734) feat(desktop): persist sidebar observed-unread across webview reload (#3976) feat(desktop): surface config diff in restart-required badge (#3637) Polish sidebar unread hierarchy (#4573) fix(desktop): show cached display names on startup (#3317) docs(acp): explain per-channel session model in base prompt (#4729) docs(nip-am): normative amendment — cache SHOULD/MUST + pricingIdentity + consumer cost guidance (#4632) Remove blur from Welcome composer guidance (#4691) Refine desktop timeline activity presentation (#4582) Defer desktop media uploads until send (#4522) fix(desktop): stop clipping focus ring on channel intro action cards (#2392) (#4374) Polish mobile inbox and media flows (#4512) feat: ship Buzz Term (#4347) ... Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
) ## Summary Increases three Playwright assertion timeouts in `tests/e2e/empty-edit-delete.spec.ts` from 5s to 10s to fix a shard-composition flake introduced by PR #4694. ## Root Cause PR #4694 added `huddle-transcription.spec.ts` (477 lines, 22+ tests) to the Desktop Smoke E2E suite, shifting shard 2 composition so that `empty-edit-delete` now runs with significantly more accumulated browser state. The three affected assertions all wait for a React state update triggered by pressing Enter in edit mode: - `alertdialog` becoming visible after an empty edit (tests 1 and 2) - `edit-target` hiding after a successful non-empty edit (test 3) These transitions go through the React scheduler. In isolation they complete in milliseconds. In a loaded headless shard with accumulated GC pressure, the 5s window became insufficient — test 3 failed 3/3 times in CI run [30946444168](https://github.com/block/buzz/actions/runs/30946444168) with `edit-target` still visible after Enter. No product code is changed. The empty-edit-delete flow is correct and untouched by #4694. This is a test-environment timing adjustment only. ## What Changed - `tests/e2e/empty-edit-delete.spec.ts` — three `{ timeout: 5_000 }` → `{ timeout: 10_000 }` for the post-Enter React-update waits ## Validation - `just desktop-check` — passed - `just desktop-test` — 4194 passed, 0 failed Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
…gent-instructions * origin/main: (30 commits) feat: Buzz entity links — rich preview cards + in-app navigation for repos, PRs, and issues (block#4695) fix(desktop): serialize tray channel actions for frontend (block#4762) chore(release): release Buzz Desktop version 0.5.5 (block#4788) feat(projects): support multiple repositories (block#4671) fix(ci): make desktop cache test version agnostic (block#4791) fix(desktop): widen post-Enter timeouts in empty-edit-delete spec (block#4792) fix(desktop): wait for terminal frame before splash (block#4781) fix(desktop): integer-align custom reaction emoji (block#4779) Polish Huddle voice controls (block#4694) fix(local-archive): default both archive settings to enabled (block#4750) fix(mobile): stop oversized read-state retry loop (block#4595) fix(desktop): close reconnect gaps that previously required CMD+R (block#4737) Dock Buzz Term within channel workspace (block#4724) perf(relay): index channel-id lookups and skip trace-only reads (block#4647) fix(agents): canonicalize stale persona harness pins (block#4631) Refine community invite links (block#4734) feat(desktop): persist sidebar observed-unread across webview reload (block#3976) feat(desktop): surface config diff in restart-required badge (block#3637) Polish sidebar unread hierarchy (block#4573) fix(desktop): show cached display names on startup (block#3317) ... Signed-off-by: Alex Rosenzweig <arosenzweig@squareup.com>
…er-snapshots * origin/main: Revert "chore(release): release Buzz Desktop version 0.5.5" (#4797) feat: Buzz entity links — rich preview cards + in-app navigation for repos, PRs, and issues (#4695) fix(desktop): serialize tray channel actions for frontend (#4762) chore(release): release Buzz Desktop version 0.5.5 (#4788) feat(projects): support multiple repositories (#4671) fix(ci): make desktop cache test version agnostic (#4791) fix(desktop): widen post-Enter timeouts in empty-edit-delete spec (#4792) fix(desktop): wait for terminal frame before splash (#4781) fix(desktop): integer-align custom reaction emoji (#4779) Polish Huddle voice controls (#4694) fix(local-archive): default both archive settings to enabled (#4750) fix(mobile): stop oversized read-state retry loop (#4595) Co-authored-by: npub14ndfusear8wdpe4kss8h7juc7wjk78atnqzf63zvppcpneknv4sq6x9370 <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz> Signed-off-by: npub14ndfusear8wdpe4kss8h7juc7wjk78atnqzf63zvppcpneknv4sq6x9370 <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz> # Conflicts: # desktop/src/features/communities/useCommunityInit.ts # desktop/src/shared/lib/linkPreview.test.mjs # desktop/src/shared/lib/linkPreview.ts # desktop/src/shared/lib/useResolvedLinkPreviews.ts # desktop/src/shared/ui/link-preview-attachment.tsx # desktop/src/shared/ui/markdown.tsx
* origin/main: (31 commits) feat: paste composer text without formatting (#4801) Revert "chore(release): release Buzz Desktop version 0.5.5" (#4808) chore(release): release Buzz Desktop version 0.5.5 (#4800) fix: reauthenticate databricks model discovery (#4008) Revert "chore(release): release Buzz Desktop version 0.5.5" (#4797) feat: Buzz entity links — rich preview cards + in-app navigation for repos, PRs, and issues (#4695) fix(desktop): serialize tray channel actions for frontend (#4762) chore(release): release Buzz Desktop version 0.5.5 (#4788) feat(projects): support multiple repositories (#4671) fix(ci): make desktop cache test version agnostic (#4791) fix(desktop): widen post-Enter timeouts in empty-edit-delete spec (#4792) fix(desktop): wait for terminal frame before splash (#4781) fix(desktop): integer-align custom reaction emoji (#4779) Polish Huddle voice controls (#4694) fix(local-archive): default both archive settings to enabled (#4750) fix(mobile): stop oversized read-state retry loop (#4595) fix(desktop): close reconnect gaps that previously required CMD+R (#4737) Dock Buzz Term within channel workspace (#4724) perf(relay): index channel-id lookups and skip trace-only reads (#4647) fix(agents): canonicalize stale persona harness pins (#4631) ... Signed-off-by: Alessandro Joabar <sandro@squareup.com>
…links * origin/main: fix(desktop): integer-align custom reaction emoji (#4779) Polish Huddle voice controls (#4694) fix(local-archive): default both archive settings to enabled (#4750) fix(mobile): stop oversized read-state retry loop (#4595) Signed-off-by: npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Co-authored-by: npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
## Summary - add a visible Stop control for interrupting agent speech - make push-to-talk available by default while preserving manual mute controls - refine agent management, muted audio states, drawer layering, and return navigation - suppress duplicate notification sounds for Huddle messages ## Why Huddles could trap users behind long agent speech, hide useful agent controls, and leave temporary Huddle state visible after the call. The drawer also regressed when the terminal substrate began painting behind the rounded app surface. ## Validation - `just desktop-ci` - focused Huddle Playwright coverage for the drawer, speech interruption, agent picker, and leave navigation --------- Signed-off-by: kenny lopez <klopez4212@gmail.com> Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> Signed-off-by: bhargavms <bhargav.m@ewa-services.com>
…ock#4792) ## Summary Increases three Playwright assertion timeouts in `tests/e2e/empty-edit-delete.spec.ts` from 5s to 10s to fix a shard-composition flake introduced by PR block#4694. ## Root Cause PR block#4694 added `huddle-transcription.spec.ts` (477 lines, 22+ tests) to the Desktop Smoke E2E suite, shifting shard 2 composition so that `empty-edit-delete` now runs with significantly more accumulated browser state. The three affected assertions all wait for a React state update triggered by pressing Enter in edit mode: - `alertdialog` becoming visible after an empty edit (tests 1 and 2) - `edit-target` hiding after a successful non-empty edit (test 3) These transitions go through the React scheduler. In isolation they complete in milliseconds. In a loaded headless shard with accumulated GC pressure, the 5s window became insufficient — test 3 failed 3/3 times in CI run [30946444168](https://github.com/block/buzz/actions/runs/30946444168) with `edit-target` still visible after Enter. No product code is changed. The empty-edit-delete flow is correct and untouched by block#4694. This is a test-environment timing adjustment only. ## What Changed - `tests/e2e/empty-edit-delete.spec.ts` — three `{ timeout: 5_000 }` → `{ timeout: 10_000 }` for the post-Enter React-update waits ## Validation - `just desktop-check` — passed - `just desktop-test` — 4194 passed, 0 failed Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> Signed-off-by: bhargavms <bhargav.m@ewa-services.com>
## Problem Humans cannot interrupt agents in huddles: agent TTS keeps playing over a talking human (reported by @tlongwell-block, 2026-08-20). The full requirement: **any human talking — local or remote, any input mode, any audio rig — must interrupt any agent on the huddle.** ## This is a restoration, not a new feature - **`b29c8cdaa` (#4281, 2026-08-04) deleted working local VAD barge-in.** The pre-image shipped `BARGE_IN_DEBOUNCE_FRAMES = 20` (320 ms sustained speech cancels TTS), live at the production call site (`pipeline.rs` passed `Some(tts_cancel)` unconditionally). The same day, `ce3cf3cd2` (#4694) flipped the default input mode from VAD to push-to-talk, which masked the loss. - **`068a83b09` (#5671, 2026-08-13) removed the remaining TTS-awareness plumbing from STT** (deliberately, to keep transcribing over agent audio — a good change). Consequence: this PR is a re-plumb through the `PlaybackCoordinator` from #6341, not a revert. - A gap that **never** worked is also closed: PTT-mode users who open the mic via the mute button (`manual_mic_unmuted` postdates the deletion) transcribed fine but could not barge in. ## Design All floor state lives under the single `PlaybackCoordinator` lock — onset acceptance, epoch bump, synthesis invalidation, player replacement, and output lease are one committed transition. No cancel flag can be observed out of order with the playback state it describes. - **Human floor**: local + per-peer remote ownership with epoch invalidation. Onset cancels playback by queue replacement; late synthesis for a stale epoch cannot append or restart. - **Local onset (VAD)**: on an **isolated output route** (all CoreAudio output-stream terminals report headphones), a confirmed short onset interrupts immediately — no echo path exists. On a **coupled route** (speakers, unknown, virtual, mixed), the restored **20-frame / 320 ms sustained-speech debounce** discriminates a real human from speaker bleed; the deleted code's comment records that 80 ms was tried and false-triggered on laptop speakers. Route classification is queried fresh at each onset (never cached — default-device re-routing mid-huddle would strand a stale verdict). - **Mic-open gate is per-frame**: barge-in observes on any frame where the mic is actually open — pure VAD mode, or PTT with the mic manually unmuted (key-held frames defer to the shortcut's own cancel). - **Remote onset**: sustained non-DTX frames from a peer enter the same persistent floor (independent of whether playback is live — a human speaking while TTS is idle blocks late-arriving synthesis from starting over them). Release on sustained DTX/absence, peer departure, and recv-loop exit, with guards so a vanished peer cannot wedge the floor. - **Output lease**: accepted appends renew an `Active` lease; drain/cancel/onset start a 100 ms tail hangover (conservative against measured ~12 ms/~1 ms CoreAudio tails), so speaker-tail bleed in the just-drained window cannot self-trigger the coupled path. ## Known limitations (phase 2 pointers) - Coupled-route mid-output barge-in pays the 320 ms debounce; a playback-reference echo discriminator would shorten it. - A speakers-rig participant's bleed can enter their mic and hold the floor for other machines (bounded by release debounce). - Non-macOS routes classify as coupled (fail-safe). ## Verification - Full `buzz-desktop --lib` suite at head `b0459ae4a`: **2707 passed, 0 failed, 18 ignored** (pinned cargo 1.95.0). - Exact CI recipe `just desktop-tauri-clippy`: PASS at head; base arm at merge-base `b728a2af3` confirms the two `#[allow(clippy::too_many_arguments)]`s cover branch-caused threshold crossings (human_floor threading), not inherited noise. - Regression tests pin: 20-frame threshold + reset-on-gap, short-coupled rejection, sustained-coupled acceptance, coupled-idle acceptance, remote-idle delayed-TTS rejection, output-tail hangover boundary (during = rejected, after = accepted), isolated onset, per-frame mic-open gate truth table, PTT+manual-unmute sustained coupled acquisition. - `LocalBargeIn::observe` is covered as two joined halves (gate truth table in `local_barge_in.rs`, floor transition in `tts_playback.rs`); its body is a straight-line wrapper around a live CoreAudio query, left uninjected deliberately. - Coverage precision (mutation-verified): `manual_open_ptt_sustained_speech_acquires_coupled_floor` pins the gate → 20-frame debounce → acquire → floor-blocked chain on the coupled-**idle** cell. The live-output override leg is carried by `sustained_coupled_speech_overrides_live_output_suppression` (tts_playback.rs); the joiner's `sustained_coupled` argument is not load-bearing there (flipping it to `false` leaves the test green, while shortening the debounce by one frame turns it red). - Live arms in progress: pre-regression build `b29c8cdaa^` staged to confirm the deleted mechanism worked; two-endpoint remote-leg test pending a second human. ## Commits 1. `fb681a5a9` — restore human barge-in (coordinator floor, lease, route isolation, remote floor, 320 ms coupled debounce) 2. `b4265418e` — enable barge-in for manually opened mics (per-frame gate; closes the PTT-open-mic gap) 3. `886489f2b` — extract local barge-in policy module (file-size ratchet; also hoists the CoreAudio route query from per-frame to per-onset, named in the commit message) 4. `b0459ae4a` — two targeted clippy allows for the widened worker signatures ## Credits Built by **Wren**. Regression archaeology and the PTT-open-mic gap by **Dawn** (who also killed her own first fix as vacuous and caught a clippy blocker before it hit CI). Review blockers (coordinator serialization, idle-onset floors, output lease) by **Mari**. Live rig verification by **Max**. Coordination and verification by **Eva**. Opened by Eva with Tyler's explicit direction; commits carry agent trailers. --------- Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz> Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
* commit 'f1181fd31': (76 commits) Polish Huddle voice controls (block#4694) fix(local-archive): default both archive settings to enabled (block#4750) fix(mobile): stop oversized read-state retry loop (block#4595) fix(desktop): close reconnect gaps that previously required CMD+R (block#4737) Dock Buzz Term within channel workspace (block#4724) perf(relay): index channel-id lookups and skip trace-only reads (block#4647) fix(agents): canonicalize stale persona harness pins (block#4631) Refine community invite links (block#4734) feat(desktop): persist sidebar observed-unread across webview reload (block#3976) feat(desktop): surface config diff in restart-required badge (block#3637) Polish sidebar unread hierarchy (block#4573) fix(desktop): show cached display names on startup (block#3317) docs(acp): explain per-channel session model in base prompt (block#4729) docs(nip-am): normative amendment — cache SHOULD/MUST + pricingIdentity + consumer cost guidance (block#4632) Remove blur from Welcome composer guidance (block#4691) Refine desktop timeline activity presentation (block#4582) Defer desktop media uploads until send (block#4522) fix(desktop): stop clipping focus ring on channel intro action cards (block#2392) (block#4374) Polish mobile inbox and media flows (block#4512) feat: ship Buzz Term (block#4347) ... Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…er-snapshots * origin/main: Revert "chore(release): release Buzz Desktop version 0.5.5" (block#4797) feat: Buzz entity links — rich preview cards + in-app navigation for repos, PRs, and issues (block#4695) fix(desktop): serialize tray channel actions for frontend (block#4762) chore(release): release Buzz Desktop version 0.5.5 (block#4788) feat(projects): support multiple repositories (block#4671) fix(ci): make desktop cache test version agnostic (block#4791) fix(desktop): widen post-Enter timeouts in empty-edit-delete spec (block#4792) fix(desktop): wait for terminal frame before splash (block#4781) fix(desktop): integer-align custom reaction emoji (block#4779) Polish Huddle voice controls (block#4694) fix(local-archive): default both archive settings to enabled (block#4750) fix(mobile): stop oversized read-state retry loop (block#4595) Co-authored-by: npub14ndfusear8wdpe4kss8h7juc7wjk78atnqzf63zvppcpneknv4sq6x9370 <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz> Signed-off-by: npub14ndfusear8wdpe4kss8h7juc7wjk78atnqzf63zvppcpneknv4sq6x9370 <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz> # Conflicts: # desktop/src/features/communities/useCommunityInit.ts # desktop/src/shared/lib/linkPreview.test.mjs # desktop/src/shared/lib/linkPreview.ts # desktop/src/shared/lib/useResolvedLinkPreviews.ts # desktop/src/shared/ui/link-preview-attachment.tsx # desktop/src/shared/ui/markdown.tsx
## Summary - add a visible Stop control for interrupting agent speech - make push-to-talk available by default while preserving manual mute controls - refine agent management, muted audio states, drawer layering, and return navigation - suppress duplicate notification sounds for Huddle messages ## Why Huddles could trap users behind long agent speech, hide useful agent controls, and leave temporary Huddle state visible after the call. The drawer also regressed when the terminal substrate began painting behind the rounded app surface. ## Validation - `just desktop-ci` - focused Huddle Playwright coverage for the drawer, speech interruption, agent picker, and leave navigation --------- Signed-off-by: kenny lopez <klopez4212@gmail.com> Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
…ock#4792) ## Summary Increases three Playwright assertion timeouts in `tests/e2e/empty-edit-delete.spec.ts` from 5s to 10s to fix a shard-composition flake introduced by PR block#4694. ## Root Cause PR block#4694 added `huddle-transcription.spec.ts` (477 lines, 22+ tests) to the Desktop Smoke E2E suite, shifting shard 2 composition so that `empty-edit-delete` now runs with significantly more accumulated browser state. The three affected assertions all wait for a React state update triggered by pressing Enter in edit mode: - `alertdialog` becoming visible after an empty edit (tests 1 and 2) - `edit-target` hiding after a successful non-empty edit (test 3) These transitions go through the React scheduler. In isolation they complete in milliseconds. In a loaded headless shard with accumulated GC pressure, the 5s window became insufficient — test 3 failed 3/3 times in CI run [30946444168](https://github.com/block/buzz/actions/runs/30946444168) with `edit-target` still visible after Enter. No product code is changed. The empty-edit-delete flow is correct and untouched by block#4694. This is a test-environment timing adjustment only. ## What Changed - `tests/e2e/empty-edit-delete.spec.ts` — three `{ timeout: 5_000 }` → `{ timeout: 10_000 }` for the post-Enter React-update waits ## Validation - `just desktop-check` — passed - `just desktop-test` — 4194 passed, 0 failed Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
…#6431) ## Problem Humans cannot interrupt agents in huddles: agent TTS keeps playing over a talking human (reported by @tlongwell-block, 2026-08-20). The full requirement: **any human talking — local or remote, any input mode, any audio rig — must interrupt any agent on the huddle.** ## This is a restoration, not a new feature - **`af68c34e7` (block#4281, 2026-08-04) deleted working local VAD barge-in.** The pre-image shipped `BARGE_IN_DEBOUNCE_FRAMES = 20` (320 ms sustained speech cancels TTS), live at the production call site (`pipeline.rs` passed `Some(tts_cancel)` unconditionally). The same day, `5a361f99e` (block#4694) flipped the default input mode from VAD to push-to-talk, which masked the loss. - **`5214a0755` (block#5671, 2026-08-13) removed the remaining TTS-awareness plumbing from STT** (deliberately, to keep transcribing over agent audio — a good change). Consequence: this PR is a re-plumb through the `PlaybackCoordinator` from block#6341, not a revert. - A gap that **never** worked is also closed: PTT-mode users who open the mic via the mute button (`manual_mic_unmuted` postdates the deletion) transcribed fine but could not barge in. ## Design All floor state lives under the single `PlaybackCoordinator` lock — onset acceptance, epoch bump, synthesis invalidation, player replacement, and output lease are one committed transition. No cancel flag can be observed out of order with the playback state it describes. - **Human floor**: local + per-peer remote ownership with epoch invalidation. Onset cancels playback by queue replacement; late synthesis for a stale epoch cannot append or restart. - **Local onset (VAD)**: on an **isolated output route** (all CoreAudio output-stream terminals report headphones), a confirmed short onset interrupts immediately — no echo path exists. On a **coupled route** (speakers, unknown, virtual, mixed), the restored **20-frame / 320 ms sustained-speech debounce** discriminates a real human from speaker bleed; the deleted code's comment records that 80 ms was tried and false-triggered on laptop speakers. Route classification is queried fresh at each onset (never cached — default-device re-routing mid-huddle would strand a stale verdict). - **Mic-open gate is per-frame**: barge-in observes on any frame where the mic is actually open — pure VAD mode, or PTT with the mic manually unmuted (key-held frames defer to the shortcut's own cancel). - **Remote onset**: sustained non-DTX frames from a peer enter the same persistent floor (independent of whether playback is live — a human speaking while TTS is idle blocks late-arriving synthesis from starting over them). Release on sustained DTX/absence, peer departure, and recv-loop exit, with guards so a vanished peer cannot wedge the floor. - **Output lease**: accepted appends renew an `Active` lease; drain/cancel/onset start a 100 ms tail hangover (conservative against measured ~12 ms/~1 ms CoreAudio tails), so speaker-tail bleed in the just-drained window cannot self-trigger the coupled path. ## Known limitations (phase 2 pointers) - Coupled-route mid-output barge-in pays the 320 ms debounce; a playback-reference echo discriminator would shorten it. - A speakers-rig participant's bleed can enter their mic and hold the floor for other machines (bounded by release debounce). - Non-macOS routes classify as coupled (fail-safe). ## Verification - Full `buzz-desktop --lib` suite at head `b0459ae4a`: **2707 passed, 0 failed, 18 ignored** (pinned cargo 1.95.0). - Exact CI recipe `just desktop-tauri-clippy`: PASS at head; base arm at merge-base `8f2b659fe` confirms the two `#[allow(clippy::too_many_arguments)]`s cover branch-caused threshold crossings (human_floor threading), not inherited noise. - Regression tests pin: 20-frame threshold + reset-on-gap, short-coupled rejection, sustained-coupled acceptance, coupled-idle acceptance, remote-idle delayed-TTS rejection, output-tail hangover boundary (during = rejected, after = accepted), isolated onset, per-frame mic-open gate truth table, PTT+manual-unmute sustained coupled acquisition. - `LocalBargeIn::observe` is covered as two joined halves (gate truth table in `local_barge_in.rs`, floor transition in `tts_playback.rs`); its body is a straight-line wrapper around a live CoreAudio query, left uninjected deliberately. - Coverage precision (mutation-verified): `manual_open_ptt_sustained_speech_acquires_coupled_floor` pins the gate → 20-frame debounce → acquire → floor-blocked chain on the coupled-**idle** cell. The live-output override leg is carried by `sustained_coupled_speech_overrides_live_output_suppression` (tts_playback.rs); the joiner's `sustained_coupled` argument is not load-bearing there (flipping it to `false` leaves the test green, while shortening the debounce by one frame turns it red). - Live arms in progress: pre-regression build `af68c34e7^` staged to confirm the deleted mechanism worked; two-endpoint remote-leg test pending a second human. ## Commits 1. `fb681a5a9` — restore human barge-in (coordinator floor, lease, route isolation, remote floor, 320 ms coupled debounce) 2. `b4265418e` — enable barge-in for manually opened mics (per-frame gate; closes the PTT-open-mic gap) 3. `886489f2b` — extract local barge-in policy module (file-size ratchet; also hoists the CoreAudio route query from per-frame to per-onset, named in the commit message) 4. `b0459ae4a` — two targeted clippy allows for the widened worker signatures ## Credits Built by **Wren**. Regression archaeology and the PTT-open-mic gap by **Dawn** (who also killed her own first fix as vacuous and caught a clippy blocker before it hit CI). Review blockers (coordinator serialization, idle-onset floors, output lease) by **Mari**. Live rig verification by **Max**. Coordination and verification by **Eva**. Opened by Eva with Tyler's explicit direction; commits carry agent trailers. --------- Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz> Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>



Summary
Why
Huddles could trap users behind long agent speech, hide useful agent controls, and leave temporary Huddle state visible after the call. The drawer also regressed when the terminal substrate began painting behind the rounded app surface.
Validation
just desktop-ci