crates/namir-clap/src/main_thread.rs:81, src/audio.rs:163-178
Every activate() builds a default engine, announces its latency (0), and dispatches spawn_recall to reload the model asynchronously. When the recalled model engages D-9.2's resampler, publish_latency (audio.rs:105) sees the change, flags dirty and requests a callback; on_main_thread finds active == true and calls request_restart(). The restart deactivates and reactivates, producing another default engine at latency 0, another recall, another change, another restart -- indefinitely, for as long as a rate-mismatched model is loaded.
tests/clap_host_latency.rs walks precisely this path and sidesteps the loop: at limb 3 it deactivates (:400-401) before servicing the second callback, so the active branch is never re-entered.
Fix: keep the last-reported-to-host latency in SharedInner across activations and skip request_restart when the new reading equals it -- or defer activate()'s announcement until the recall has converged.
crates/namir-clap/src/main_thread.rs:81,src/audio.rs:163-178Every
activate()builds a default engine, announces its latency (0), and dispatchesspawn_recallto reload the model asynchronously. When the recalled model engages D-9.2's resampler,publish_latency(audio.rs:105) sees the change, flags dirty and requests a callback;on_main_threadfindsactive == trueand callsrequest_restart(). The restart deactivates and reactivates, producing another default engine at latency 0, another recall, another change, another restart -- indefinitely, for as long as a rate-mismatched model is loaded.tests/clap_host_latency.rswalks precisely this path and sidesteps the loop: at limb 3 it deactivates (:400-401) before servicing the second callback, so theactivebranch is never re-entered.Fix: keep the last-reported-to-host latency in
SharedInneracross activations and skiprequest_restartwhen the new reading equals it -- or deferactivate()'s announcement until the recall has converged.