3edff3304b
- Process-wide CipConnection statics (ForwardOpenCount, Forward Close counts, RequestsSent, exchange stats, OpenAttempts, OpenAttemptBudget) move to an instance ConnectionDiagnostics owned by each DeviceSessionPool (and by a stand-alone CipConnection). The open-attempt budget becomes a disposable per-DeviceKey limit (LimitOpenAttempts); the differential harness scopes one to the press under test. - LibplctagOrphanRelease.ForceRootingForTest is gone: ReleaseIfOrphaned(tag, canReadHandles) overload. - A connected reply with general 0x01 / extended 0x0107 or 0x0203 (target no longer holds the class-3 connection, TCP still up) retires the session at once; the next send reopens through the throttle. - New tests: dispose during RegisterSession, abandoned-open observer (falsified), scheduler-dispose-throws guard (DeviceSessionPool.CloseAsync), release-in-background with a shared open in flight, per-device limit scoping, CIP-close recycle (request + keep-alive + negative control). Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe