Squashed integration of the user-facing message audit for this surface set.
Full per-finding receipts: /tmp/ux-audit/lanes/*-receipt.md (campaign artifacts).
Switching to GPT-Live meant Settings → Voice → Voice Chat Mode, which is not
where you are when you want to talk. The composer now offers the choice where
the voice button is:
- folded layout (HUD / narrow): a "Voice chat engine" radio group in the
existing voice menu
- unfolded layout: a small chevron beside the start-voice button opening the
same rows; the button tooltip names the engine that will mount
Rows are hidden until the backend reports a mode (older gateway = no switch
that would 4002); GPT-Live is disabled with the backend's reason when no
OpenAI key resolves. Selecting writes `voice.voice_chat_mode` through
`config.set` on the LIVE gateway (local, SSH, cloud alike) and re-reads the
resolved status; it applies to the next conversation and never touches a
running one.
Backend: `voice.voice_chat_mode` joins the `config.set` word setters
(chained|gpt-live).
Live: headed desktop, chained → menu → GPT-Live → start = RTCPeerConnection
connected; menu → chained → start = no peer connection, chained controls.
Carry the one hunk PR #106424 adds over #106405: the 4001 message names the
door that deliberately changes the profile default, so a stale client's user
sees where to go instead of a bare "requires a live session". The flag
pre-parse from #106424 is not carried: with #106405's guard, sessionless
`--once --global` already surfaces the canonical conflict error through
_apply_model_switch (verified in-process).
Co-authored-by: mkrb84 <192544766+mkrb84@users.noreply.github.com>
tools/approval.py no longer re-exports sibling names (approval_context/prompt/floors/detection/
human_wait/smart/gateway_wait); it imports only what it uses. Siblings reference sibling-defined
names directly (module-attribute reads on tools.approval_context so patching the defining module
still works); only facade-owned state (_lock, _gateway_queues, _permanent_approved, _denied,
_denial_breaker_addendum, _gateway_notify_cb) is still read back through tools.approval.
approval_detection calls its own _command_detection_variants instead of late-binding through the facade.
For each issue anchor present in BASE 63279301bc non-test .py and absent on HEAD, the BASE comment/docstring block was re-attached at the HEAD location of the code it explained (matched by the distinctive code line / enclosing def). Sentences already covered by an existing HEAD comment were deduped; the issue number always survives. Insert-only: no code lines changed.