Hands-free voice mode had no language signal at all, so every spoken reply was
synthesized with the English voice no matter what the user actually said. The
multilingual Piper work (PR #26) added server-side routing for a "language"
field but nothing ever sent one.
Carry the language the private Jetson Whisper service already detects through
to the TTS request for the reply that speech produced, and only for that reply.
hermes-stt returns {text, model, language}, accepted only as a bare ISO-639
token; hermes_stt_client.py writes a <stem>.language sidecar next to the .txt
transcript Hermes reads, leaving the local-command contract intact; the
patched local-command envelope and /api/transcribe re-validate it and surface
it; atlas-voice.js binds it to the voice-mode generation token and chat
session, consumes it exactly once, and clears it on cancellation, restart,
session change, empty transcript or transcription error; /api/tts honours it
only from the fixed en/ru/es allow-list and otherwise sends English.
A client "voice" field is never read at any hop, and typed messages, the manual
read-aloud button, and any reply not produced by a spoken turn carry no trusted
signal and stay on the English voice.
The two WebUI-side and one agent-side edits are fail-closed replace_exact
patches; both patch roots are now env-overridable so the contract can be
verified offline without a GPU or an image build.
Document what an operator needs to know about the repairs: why the ordinal
workspace claim is ReadWriteMany and why colocation is only a preference, that
`lease_failed` is retryable rather than terminal and what a persistent deferred
park means, why a retry publishes an attempt-scoped ref and what to expect from
the extra drafts, and why the best-effort pool is deliberately absent from the
hermes Kustomization health checks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three fenced worker Pods claim Hermes Kanban runs through a coordinator that
owns every state transition, with per-ordinal HMAC authority, a mediated
broker-only SCM path, and durable per-ordinal workspaces.
Content is the reviewed head of PR #18 (689bcb6e) with PR 16's and PR 19's
contributions removed: they were merged in only to validate co-existence and are
not prerequisites, so this branch no longer carries them as ancestors. Only PR 14
and PR 15 remain, because the broker boundary and the cli_lane_* decomposition
are load-bearing for two of the fixed P0 boundaries.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>