Merge hw4-udtwrite (#592/#611)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe

# Conflicts:
#	docs/drivers/AbCip.md
This commit is contained in:
Joseph Doherty
2026-10-09 04:32:03 -04:00
12 changed files with 970 additions and 25 deletions
+13 -5
View File
@@ -43,16 +43,22 @@ libplctag passed on all seven profiles; on `micro800` libplctag failed on the em
smoke test passes on both transports. Evidence:
[native-ab-transport-gate-results](../plans/2026-10-07-native-ab-transport-gate-results.md).
- Write-capable tests (the Logix Emulate ALMD test) require `AB_SERVER_ALLOW_WRITES=1` and refuse while
`AB_DIFF_ENDPOINT` is set.
- Write-capable tests (the Logix Emulate ALMD test, and `AbCipUdtMemberWriteTests` — #611 discovered-member
writes, both transports, against the `UdtSeg.*` member tags of the `controllogix` profile) require
`AB_SERVER_ALLOW_WRITES=1` and refuse while `AB_DIFF_ENDPOINT` is set.
- **Differential harness** (`AbCip.IntegrationTests/Differential`, `LiveIntegration`) compares libplctag and
native on browse, template and read parity against one endpoint. It is read-only by construction, aborts on
the first connection failure, never retries, and caps the native phase at one Forward Open. Env:
`AB_DIFF_ENDPOINT`, `AB_DIFF_PATH`, `AB_DIFF_FAMILY`, `AB_DIFF_TAGS`, `AB_DIFF_MAX_TAGS` (at most 500),
`AB_DIFF_MAX_TEMPLATES`, `AB_DIFF_PACE_MS` (default 20), `AB_DIFF_COUNT_OPENS`. Always run with
`--filter "FullyQualifiedName~Differential"` and `AB_SERVER_ENDPOINT=127.0.0.1:1`.
- ab_server serves no UDTs and refuses 1-byte writes, so template parity is vacuous there and BOOL/SINT
parity is weak evidence. Native writes remain simulator-only.
- ab_server serves no UDTs, so template parity is vacuous there. Docker patch 0003 serves a UDT **member
path** from a flat tag named by that dotted path (`UdtSeg.ID`, `UdtSeg.Sub.Code`, `UdtSeg.Points[2]`) — the
wire of a member read/write, not a structure — and accepts the pad byte libplctag adds to a 1-byte write,
which stock ab_server refused (`0x03`) for every libplctag BOOL/SINT write. Two blind spots follow (see
the Docker README §0003): a +1-byte over-write of an odd-sized tag is no longer caught, and a malformed
single segment `"UdtSeg.ID"` resolves where a real Logix would refuse it. Native writes remain
simulator-only.
- **Golden-frame capture:** `scripts/ab-capture/capture.sh` (capture client in `scripts/ab-capture/client`);
fixtures live in `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport.Tests/Captures/` with a README.
@@ -76,7 +82,9 @@ ControlLogix profile `Notes`: *"ab_server lacks full UDT emulation."*
Unverified against `ab_server`:
- PR 6 structured read/write (`AbCipStructureMember` fan-out)
- PR 6 structured read/write (`AbCipStructureMember` fan-out) — except the **member-path wire** of a
write, which patch 0003 serves (`AbCipUdtMemberWriteTests`, #611); offsets and BIT-member semantics are
not emulated
- #179 Template Object shape reader (`CipTemplateObjectDecoder` + `FetchUdtShapeAsync`)
- #194 whole-UDT read optimization (`AbCipUdtReadPlanner` +
`AbCipUdtMemberLayout` + the `ReadGroupAsync` path in `AbCipDriver`)