Addresses the four unresolved P2 review threads on #106002.
- Readiness barrier: the recorder stop() and the conversation loop turn
paths await the warm-up issued at mic-open before submitting audio to
transcription, so a cold model load settles inside the lease request own
budget instead of eating the transcription request 180s decode deadline
(#105955 review).
- Warm-only idle eviction: warm_stt_provider() registers the warmed model
with the existing idle-unload watcher, so stt.local.unload_after_idle_seconds
is enforced for a model loaded only by warm-up (mic open then cancel) and on
reload after a prior watcher exited.
- Readiness is validated, never remembered: the lease dedupe now separates
registration from warm-up validation — an HTTP 200 action "error" body
clears readiness and retries the next acquire, and a validated warm-up is
only trusted for a short window so an idle eviction mid-conversation
re-warms on the next listening start. Cloud noop stays a valid outcome.
- Lease ownership: queued operations and dedupe state key on the owning
connection/profile captured at intent time and carried through the wire
call (setSttLease gains the same owner scope speakText uses), so switching
gateway/profile mid-flight releases the lease on the backend that holds it
and a new owner acquire warms its own backend.