* fix(audio): stop near-silent renders becoming "blank noise" + guard archetypes
Root cause of the blank/hiss voices: normalize_audio peak-normalized to -2 dBFS
whenever max(|audio|) > 0. When the model emits a near-silent clip (peak at the
noise floor, e.g. 1e-4), that applies thousands of × of gain and lifts the
noise floor to full scale — silence turned into loud hiss. This affected every
generation path (clone/dub/design/archetypes), which is why "some voices" came
out as blank noise.
- services/audio_dsp.py: normalize_audio gains a -50 dBFS silence floor. At or
below it the audio is left untouched (stays inaudible) instead of being
amplified. Real speech — even a whisper — peaks well above the floor, so
normal output is unchanged.
- api/routers/archetypes.py: after rendering, _is_blank_audio() detects a dead
clip (empty / non-finite / peak < 0.02 — a real normalized clip peaks ~0.79).
The render retries once with a different seed, then fails loudly (503 via the
existing handlers) so a blank preview or voice profile is never cached/saved.
Also extracts the script with a non-empty fallback.
- core/archetypes.py: _build never falls back to an empty script (empty text
synthesizes to silence).
Tests (tests/, runs in CI): normalize_audio doesn't amplify silence but still
normalizes real audio to target; _is_blank_audio flags dead renders and passes
real audio; every archetype carries a non-empty sample script.
Verified: full tests/ suite 601 passed incl. 8 new (the 2 test_supertonic3
failures are pre-existing on main — local .venv engine/license state, green in
CI — and unrelated to this diff).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(gallery): static log message in blank-render retry (clears py/clear-text-logging)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>