A stuck narration voice no longer holds up every demo

On 21 October, from 11:01 on, no demo got its narration, and the voice sample in the configuration dialog hung too. Here is what happened and what changes.

What happened

10:55Obeya loads the English Qwen3 voice for the renders and serves clips.
≈ 11:00The voice gets a clip and never answers. It sits at 0 % CPU; Obeya waits for its reply with no time limit.
11:01The German sample from the configuration dialog queues behind that clip. So do the clips of every render that starts later (11:02, 11:12, 11:30).
11:43Still the same: the English voice is alive, its CPU time hasn't moved, and no German voice was ever started.
11:45The voice process is killed by hand. Obeya starts a new one, and all the waiting demos are rendered within minutes.

The cause

The switch to German was not the cause. Obeya never got as far as the sample, because the English voice was never ended for it. The cause was a voice that stopped answering in the middle of a clip, while Obeya waited for it with no time limit. Clips are served one at a time, so everything else queued behind that one clip.

Why the voice process itself stalled can't be found out anymore: it had been killed before anyone looked at its state. Its stderr showed no error.

What changes

Reproduced in a test

Two English renders and a German sample, with a fake voice that never answers one of the clips:

Before

(fail) a voice that stops answering
  › fails its clip after a while, and the
    sample … get their turn
  ^ this test timed out after 5000ms.

Everything waits, the sample too.

After

a:a1 hängt → the voice said nothing for
             0.4 s while making a clip
             and was ended
b:b1 ok · sample (de) ok
a:a2 ok · b:b2 ok

The stuck clip fails. The sample and the other clips are served.

Checked with the real voice

Real Qwen3 voice on this Mac, two English renders, with a German sample in the middle:

1.9 s  English voice loaded
4.4 s  ends (another voice is asked for) → German voice loaded in 1.9 s → sample ok
7.3 s  ends → English voice loaded in 1.6 s → remaining clips ok
13.9 s done

Switching voices while renders wait works, and it adds about 2 s per switch.