CIP codec (#564): PatchU16 bounds guard; CipReply content equality; CipPath
port/length/ASCII/odd/oversize validation with ArgumentException for malformed
tag names and routes; CipPath.MessageRouter/ConnectionManager are now
ReadOnlySpan<byte>; refused Forward Open surfaces ForwardOpenRefusedException
with structured general/extended status; test CaptureFile uses BinaryPrimitives.
EncapsulationClient (#565): frame write bounded by the exchange timeout, which
faults (never cancels) the connection; finite positive timeouts enforced at
every entry point; gate wait bounded by the timeout; deterministic reorder of
the 300 ms test; new dispose-during-drain, gate-wait and RegisterSession
zero-context tests.
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
Review round 1 on the golden frames:
- Re-captured logix-read-dint-array16 (element i = ((i+1)<<24)|(i+1)) and
logix-read-bool (= 1) so neither decode oracle is all zeros. ab_server rejects
libplctag's own BOOL write with CIP 0x03 (two data bytes for a one-byte BOOL),
so the BOOL is seeded by a raw UCMM Write Tag (client seed-bool).
- Committed the capture client as scripts/ab-capture/client (outside the slnx,
CPM off, libplctag 1.5.2 pinned); capture.sh gains a `client` subcommand.
- README documents simulator-only behaviour: zeroed reply sender context, STRING
typed D0 00 instead of A0 02 + handle, and the BOOL write refusal.
- capture.sh no longer claims UnregisterSession reaches the wire (session ends in RST).
- CaptureFileTests also check the CPF walk ends at the frame end and that every
reply service is its request service | 0x80.
17 .hex fixtures captured from libplctag 1.5.2 (native 2.6.0) against
otopcua-ab-server:libplctag-release, plus the CaptureFile loader, its
length/alternation tests, and the re-runnable scripts/ab-capture/capture.sh.
Observed and recorded in Captures/README.md "Routing observed":
- Micro800 is NOT UCMM under libplctag 2.6.0: it opens a Large Forward Open
(path 20 02 24 01) and reads connected; use_connected_msg=0 is ignored.
- SLC500/MicroLogix/PLC-5 send Execute PCCC 0x4B unconnected and unwrapped;
a configured path=1,0 never reaches the wire.
- Only Large FO 0x5B was observed; no 0x54 fallback occurred.
- LogixPccc is unreachable against ab_server (CIP 0x08); no fixture committed.