Status: Shipped
PR: #99
Depends on: milestones/av-sync-scene-spec.md (PR #98),
milestones/manim-lint-config.md (PR #82)
TTSGeneratorprinted Wrote aftersynthesize_speecheven when the provider wrote a 0-byte mp3 (or no file). Downstream timestamps then ran against empty audio. Chat already fails closed on empty text; TTS did not.- xAI
_grok_ttswrote whatever bytes came back, including empty. tts.model/tts.voice/tts.instructionsas a YAML list loaded and were passed to the API (instructions:as a bullet list is a common typo).tts.instructionsis typedstr.
Fail closed at config load for non-string TTS fields. Fail closed after synthesize if the mp3 is missing or empty (unlink the empty file). Grok TTS raises on an empty HTTP body.
- Present
tts.model/tts.voicemust be non-empty YAML strings. - Present
tts.instructionsmust be a YAML string (empty string allowed). -
TTSGeneratorraisesTTSErrorand removes a 0-byte output file. - xAI TTS raises
AIErroron an empty body (does not write the file). - Tests for list-valued fields, empty provider output, empty Grok body.
-
ruff check src/ tests/ -
pytest tests/ -
docgen benchmark(no clock change)
- Wizard PUT of empty narration still writes the file (lint/TTS catch later).
wizard.system_prompt/llm_modeltype gating is separate.- Missing
ttskeys still use the built-in defaults.