Review follow-up on the Bot voice routing (#100864, salvage #101545 @FalconOrtiz).
- Owner identity is (connection, profile) per the Bot Mode standing ruling:
ComposerScope publishes `connectionId` beside `profile`; `voice-client-direct`
keys its config cache and `hermesApi` scope on both (new `ownerScoped` in
api/client.ts, beside `profileScoped`), and `voice-playback` mints the
speak-stream against the OWNER connection (`getConnectionFor`) and pins the
POST fallback the same way. Two `default` Bots on two gateways no longer
collide in the cache or mint against the active gateway.
- Main pane: `ChatRuntimeBoundary` publishes the session owner hint's
(connection, profile) on the composer scope when the ambient scope has no
owner, so a Bot chat opened in place (openStoredBotChat) speaks with its
owner voice; a tile's scope already names its owner and is kept as is.
- Tests: the two direct helper tests are folded into (1) a production-path
test that renders useAutoSpeakReplies under a Bot scope and asserts every
REST audio leg carries the owner (red when the hook's wiring is reverted to
base AND when only `profile` is threaded), and (2) the routing test on
resolveSpeakStreamUrl with an owner object.
- Docs: the fallback sentence matches the code (profile server defaults, active
profile only for ownerless chats); STT stays on the active profile.
Co-authored-by: FalconOrtiz <falcon.ortiz11@gmail.com>