eb0cc27201
On Windows every Hermes process (gateway, serve, TUI/slash workers, MCP servers, CLI commands) writes the shared rotating logs through concurrent-log-handler's cross-process rotation lock. When the emitting thread is an asyncio event loop, a lock wait blocks the loop — stalling it for seconds and dropping WebSocket clients (the 'gateway keeps going down' symptom seen in #58265). Route every file handler through a single QueueListener on a dedicated thread: loggers only enqueue (non-blocking); the listener does the file I/O and rotation-lock wait off the hot path. The QueueHandler funnels via the root logger; per-handler levels and component filters are preserved by respect_handler_level + handler.handle on the listener thread. An atexit hook stops the listener before logging.shutdown closes the file handlers. - _NonFormattingQueueHandler passes the raw record (in-process queue) so target handlers apply their own RedactingFormatter/filters. - flush_log_queue() drains synchronously (shutdown + tests). - rotating_file_handlers() exposes the handlers now behind the listener; tests updated to use it. Extends the #58265 fix: the provider-key warn-storm was one amplifier of this contention; this takes the contention off the event loop entirely.