Review I2: Driver.Ab.Transport raises statuses that came off the wire in an
Execute PCCC reply (envelope CIP status, PCCC STS) as AbDeviceReplyException.
AbLegacy's IsLocalRefusal now excludes it, and the new IsAnsweredRefusal (used
by the read, write, probe and indirect-index paths) counts a wire Unsupported -
CIP 0x08/0x1C/0x20 on the envelope, STS 0x10 - as answered: per-tag
BadNotSupported, Healthy, LastSuccessfulRead advanced. Before, they landed in
the 'refused before the wire' neutral class. Pre-wire refusals are unchanged
(still neutral). A socket test covers all four codes (red before); transport
tests pin the marker and a pre-wire builder refusal as the positive control.
The AbCip Forward Open BadConnection path is untouched.
Refs #747
Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
K-F1 (AbCip #737 F1): FromCip maps general 0x1C and 0x20 to Unsupported and
0xFF/0x2104 to OutOfBounds, so a controller refusal is per-tag Bad instead of a
BadReply comms fault. A Forward Open refused with one of them is still
BadConnection. Every CIP code is now listed with its meaning; 0x01/0x07 stay
opaque on purpose.
K-F3 (AbLegacy F8, review 07 r0 I4): FromPccc follows the DF1 STS table:
0x20/0x30/0x90 -> BadConnection (a bridge reporting an unreachable END node),
0x50 and EXT 0x06 -> NotFound, EXT 0x07 -> OutOfBounds, 0x60 -> NotAllowed,
0x70/0xB0 -> DeviceStateConflict. Golden ParseReply tests per STS, and an
end-to-end AbLegacy test: STS 0x30 degrades with LastSuccessfulRead preserved;
the 0x60 positive control stays Healthy and advances it. Both were red before.
Driver edits are doc remarks and the two runtime tests the old table pinned.
Refs #747
Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT