Files
lmxopcua/tests
Joseph Doherty e5527d0201 fix(ablegacy): isolate a dead device — parallel devices, per-device backoff, single-flight connect
Review 07 P7 (High): reads walked every reference of every device serially
with no backoff, so a dead device cost Timeout per tag per poll (50 tags x 2 s
= 100 s) and starved every healthy device long enough to trip the comms-loss
watchdog against a reachable one.

- ReadAsync buckets references by device and reads up to 8 devices
  concurrently; each device's tags are still read in order.
- Each device has a ConnectionBackoff (1 s doubling to 30 s). Two consecutive
  comms faults mark it down: the rest of that pass and every later pass fail
  fast with BadCommunicationError and touch no wire until the window expires or
  any answer (data path or probe) resets it. One timing-out tag does not
  blacken its answering siblings.
- Cold connects are single-flight per device (ConnectGate), replacing the
  per-key creation locks; a cached handle never touches the gate.
- A status/exception proving the device ANSWERED with a deterministic refusal
  (not found, not allowed, out of bounds, type/size mismatch) is per-tag Bad,
  keeps its handle, warns once per tag and advances LastSuccessfulRead instead
  of evicting and degrading. Writes classify the same way.
- Health is written once per read: Degraded if any device faulted, Healthy if
  anything read Good, LastSuccessfulRead advanced when any device answered.

Adds an env-gated ab_server case with a blackholed sibling device.

Refs #738
Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
2026-10-22 14:33:54 -04:00
..