92171a01ec
Review 07 H13: _devices and _tagsByRawPath were plain dictionaries cleared and refilled in place while the retained poll loop, the actor's GetHostStatuses and server reads enumerated them. Both are now built locally and published by reference under a lifecycle lock; teardown swaps in empty tables. Lane A contract: ShutdownAsync and Dispose each retire a disjoint set of device states, so Dispose running concurrently with a still-joining ShutdownAsync is safe. A lifecycle epoch makes an InitializeAsync that the runtime abandoned (overlapping the next ShutdownAsync) refuse to publish its tables, start probe loops or write health. A runtime cached on an already-retired device state by an in-flight read is disposed instead of leaked, and late reads/writes no longer overwrite shutdown's health. Per-key semaphores are no longer disposed under callers that may still hold them. Refs #738 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT