Throw InvalidOperationException at InitializeAsync when a tag's DeviceHostAddress does not match any entry in the Devices list, naming both the tag and the unresolved host. Previously the missing-device check was guarded by a TryGetValue so a typo silently bypassed capability-matrix validation and deferred the error to per-read BadNodeIdUnknown — the opposite of the documented "fail at load" goal. Also resolves findings 004, 005, and 006 in the same file: - 004: DiscoverAsync now unconditionally emits ViewOnly for all user tags; the Writable config field no longer influences security class because the wire backend always returns BadNotWritable. - 005: All _health reads use Volatile.Read and all writes use Volatile.Write so concurrent readers observe a consistent reference and read-modify-write sequences capture a stable snapshot. - 006: EnsureConnectedAsync disposes and nulls any existing non-connected client before creating a fresh one, preventing ObjectDisposedException loops after a HandleRecycle race or teardown. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
47 KiB
47 KiB