memory: snapshot — dots-tts + config-voices/two-voice split shipped; WT #401 personal-WT deadlock routed
Captures this session's durable state: the RP-voice rebuild (chatterbox->dots v0.22.2, config-driven voices + two-voice dialogue/narration split v0.22.3) and the personal WT :8081 deadlock recovery + root-cause routing to worldtree-dev (WT #401). New substrate foot-guns: dots :8198 is a fleet switchboard, dots' language validator is an alias-mapper, per-origin TTS toggle, WT hang signature, dots-streaming-pcm-not-headerless. Three detail files added under persistent-memory.d/.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
`[2026-08-12]` **Config-driven voices + two-voice dialogue/narration split SHIPPED (v0.22.3, `5c3d0ad`).**
|
||||
|
||||
Operator ask: "we need rata side config of voices too" + "tempted to do two voices — one for
|
||||
dialogue, one for non-dialogue." Chose (via AskUserQuestion) "config + two-voice together now."
|
||||
|
||||
**Config (retires the hardcoded `_TTS_VOICE_MAP`):** `~/.config/ratatoskr/voices.json`, beside
|
||||
`local_agents.json`/`provider.env` (NOT folded into the agent-index schema — isolated from its
|
||||
v1→v2 silent-drop foot-gun). Schema:
|
||||
`{"default":"<v>","agents":{"<agent_id>":{"voice":"<v>","narration_voice":"<v>"?}}}`. Absent/malformed
|
||||
→ built-in `DEFAULT_VOICE_CONFIG`, logged, never crashes (INV-TTS-5). Initial: donut→donut;
|
||||
sindra→miranda dialogue + emmie narration.
|
||||
|
||||
**Two-voice = the presence of `narration_voice` is the split switch** (dropped the operator's
|
||||
proposed `dialogue_only` flag — an agent with no narration_voice is single-voice, which is why
|
||||
dialogue-only Donut needs no special-casing). `segment_dialogue` splits on quotes (straight `"`
|
||||
+ curly `“ ”`; apostrophes never split a word): quoted = dialogue → `voice`, rest = narration →
|
||||
`narration_voice`. Known limit: if a mixed persona speaks WITHOUT quotes, it reads as narration.
|
||||
|
||||
**Synthesis (`tts_stream_stitched` replaced `tts_stream`):** spans synth SERIALLY (dots
|
||||
single-consumer), span 0 verbatim (wav header+PCM), spans 1..N header-stripped
|
||||
(accumulate-until-`data`) → one gapless 48kHz stream with a single leading header (INV-TTS-7).
|
||||
A single-span list is a byte-identical passthrough (INV-TTS-6, no single-voice regression). NOTE
|
||||
the dots-pcm-not-headless-in-stream foot-gun that forced this design (see Tried and abandoned).
|
||||
|
||||
New module `src/ratatoskr/voices.py` (`load_voice_config` / `segment_dialogue` /
|
||||
`resolve_voice_spans`); `create_app` gains `voice_config`; `entrypoint` loads it. Contract DEC-11
|
||||
+ INV-TTS-5/6/7; new `tests/test_voices.py`. **545 tests green**, new code ruff-clean. Discipline:
|
||||
contract-first + TDD + seam-check + local bug-hunt + live-verify; heid async gates SKIPPED
|
||||
(offered). Live-verified on `:8765`: Sindra mixed turn → 2 dots calls (emmie+miranda) stitched to
|
||||
one 48kHz WAV (single RIFF header); Donut single-voice unchanged. Cut as **patch** (self-contained
|
||||
feature, no downstream coordination → patch-defensible → tie-break to patch; operator declined the
|
||||
v0.23.0-minor option by saying "push it"). Builds on [[2026-08-11-tts-dots-migration]].
|
||||
Reference in New Issue
Block a user