docs(abcip): #611 live member-write gate on Z35162 (native DINT/BIT/REAL members, restored)
v2-ci / build (push) Successful in 4m47s
v2-ci / unit-tests (push) Failing after 23m3s

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-09 04:49:19 -04:00
parent 6c6800e513
commit 12aa293cdc
3 changed files with 30 additions and 11 deletions
+2 -2
View File
@@ -1087,7 +1087,7 @@ re-emit a concrete default. The defaults differ per driver (final review, 2026-1
because the driver factory AND the admin-node Test Connect probe both read it. ⚠️ So **the upgrade restart
alone moves no-key AbCip drivers to Native**; to stay on libplctag, set the node key — NOT a per-driver key
through the old AdminUI, whose typed form drops unknown keys (#576). Evidence: AbCip reads proven on a real
CompactLogix (Z-35162); scalar native writes (DINT/BOOL/REAL) proven on it once (2026-10-09, user-approved one-off, restored) — array/STRING/UDT-member and fragmented writes are `ab_server`-only.
CompactLogix (Z-35162); scalar native writes (DINT/BOOL/REAL) proven on it once (2026-10-09, user-approved one-off, restored) — and native UDT member writes (DINT/BIT/REAL, #611 gate, same day); array/STRING, libplctag member and fragmented writes are `ab_server`-only.
- **AbLegacy: an absent key resolves to `Libplctag` for every family; `Native` is opt-in** (no node key). On
a wire the native PCCC path is proven only for **N-file reads/writes and one F8 read**, all on `ab_server`;
`S:0` (the default probe), B/T/C/R/S/L/ST/A/O/I and the T/C/R sub-element offsets are encoded from the PCCC
@@ -1102,7 +1102,7 @@ once per tag — only genuine transport failures evict and degrade (a runtime `N
it used to latch `Degraded`). AbCip width-checks every scalar **write** against the controller's bytes before
sending, on both transports (#611; libplctag used to patch part of its buffer and send it all). Controller-discovered
UDT members are writable once browse-committed and authored `ReadWrite` (BIT members included — the controller
applies the bit) — ab_server-proven only, member and BIT-member writes are unverified on real hardware; whole-UDT writes are refused `BadNotSupported` by decision (`docs/drivers/AbCip.md` §Member writes). `DeviceSessionPool.Shared` logs through the
applies the bit) — native member writes incl. a BIT member are live-gated on Z35162 (2026-10-09); sibling-bit preservation and the libplctag path are ab_server-only; whole-UDT writes are refused `BadNotSupported` by decision (`docs/drivers/AbCip.md` §Member writes). `DeviceSessionPool.Shared` logs through the
host logger factory (wired in `DriverFactoryBootstrap`; the FOCAS and TwinCAT factories' `Register(registry, ILoggerFactory?)` take one too, #602 CONV-3). The AbCip `browsePageDelayMs` knob has an AdminUI field (`AbCipDriverForm` "Browse page delay (ms)"). libplctag is confined to `Libplctag*.cs` adapters by
`LibplctagConfinementGuardTests`; do not reference it elsewhere. See `docs/drivers/AbCip.md` §Transport,
`docs/drivers/AbLegacy.md` §Transport + §Wire evidence, `docs/Configuration.md` §`Drivers:AbCip`, and
+11 -9
View File
@@ -240,14 +240,14 @@ The driver has two interchangeable wire transports, selected by one `DriverConfi
- ⚠️ **Native hardware evidence is narrow.** The read-only real-press gate (Task 21, 2026-10-08) proved native reads, browse
and templates on Z-35162; a user-approved one-off on 2026-10-09 added **scalar native writes on a real CompactLogix**
(DINT `test2`, BOOL `Program:UN01_Press.xxtest`, REAL `Program:ES03_EM03_Zone3._ff_test`: write, read back, restore, all
Good). Still ab_server-only: array, STRING and UDT-member writes and fragmented writes. Mixed STRING/array/scalar
Good), and the #611 gate added **native UDT member writes** (DINT, BIT and REAL members of `_EmptyTemperatureSegment`).
Still ab_server-only: array and STRING writes, libplctag member writes, and fragmented writes. Mixed STRING/array/scalar
Multiple Service Packet reads (#582) are proven on the press (one 5-read MSP, values equal to single reads). Results:
[native-ab-transport-gate-results](../plans/2026-10-07-native-ab-transport-gate-results.md).
- **libplctag cannot be deleted yet.** Scalar native writes are proven on a CompactLogix (2026-10-09); what remains is #567
(fragmented wide-struct writes), array/STRING/UDT-member writes on hardware, and AbLegacy native (simulator-only, no PCCC hardware).
- Discovered UDT **member writes** (#611) are likewise `ab_server`-only on both transports; the
BIT-member argument rests on a read-only hardware observation (the member reads as a 1-byte `0xC1`
BOOL). See [Member writes](#member-writes) for the candidate gate tag.
(fragmented wide-struct writes), array/STRING writes on hardware, and AbLegacy native (simulator-only, no PCCC hardware).
- UDT **member writes** (#611) are proven on a real CompactLogix on the **native** transport only (2026-10-09); the
libplctag member-write path is `ab_server`-only. See [Member writes](#member-writes).
- ⚠️ RESIDUAL (#567): wide-struct **fragmented writes** (8-byte alignment) are unit-tested only. Production
presses are read-only and there is no bench controller, so this cannot be proven; it stays open until a
bench controller exists.
@@ -465,10 +465,12 @@ when it is browse-committed in `/raw`, and that tag writes like any other atomic
**libplctag** exposes only the size, cannot tell the two apart, and refuses both `BadNotSupported`. Native additionally refuses a same-width
mismatch (REAL vs DINT) from the CIP type code — see [Native transport behaviour](#native-transport-behaviour).
A refusal keeps the handle, warns once per tag and **does not touch driver health**.
- **Not verified on a real controller.** Production presses are read-only, so member writes are proven on
`ab_server` only (Docker patch 0003 serves member paths). A candidate for a future *approved* write gate:
Z-35162 controller tag `_EmptyTemperatureSegment` (`UDT_TemperatureProfile_Segment`), which no logic
references — its members (`ID`, `Enable`, `RampTime`, …) are all zero and resolve as described above.
- **Live gate (2026-10-09, user-approved, native transport, restored):** on Z-35162, controller tag
`_EmptyTemperatureSegment` (`UDT_TemperatureProfile_Segment`, referenced by no logic) — `ID` (DINT) 0→4242→0,
`Enable` (BIT member) false→true→false, `HoldTime` (REAL) 0→42.5→0; every write and read Good, and a full snapshot
of all ten members after each write and restore showed only the written member changed. The BIT member is the
only BIT in that UDT, so preservation of *sibling bits in the same host SINT* is still `ab_server`-proven only.
The libplctag member-write path was not exercised on hardware (ab_server only, Docker patch 0003).
Pre-declared `Members` with `Writable: true` keep working as before — same write path, now width-checked
(a mistyped declared member is refused where libplctag used to write it).
@@ -559,3 +559,20 @@ bit 5, clears bit 3, asserts the whole word each time so neighbour bits are prov
writes are refused before the wire (#571, `NativeAbLegacyTagRuntime.WriteRefusal`). The test pins it. It is not the original
observation.
- No fix, so no revert-to-red proof; the test would fail if the word RMW clobbered neighbour bits.
## #611 UDT member-write gate — 2026-10-09 (user-approved, native transport)
Target: Z-35162, controller tag `_EmptyTemperatureSegment` (`UDT_TemperatureProfile_Segment`; no routine, alias or
trend references it in the 2026-09-11 L5X export; not in the Galaxy map). Tool: AbCip CLI from master `6c6800e5`,
`ab://10.209.70.160/1,0`, family CompactLogix, default (native) transport. Each leg: write, snapshot all ten members,
restore, snapshot again.
| Member | Type | Before | Wrote | Read back | Restored | Other 9 members |
|---|---|---|---|---|---|---|
| `ID` | DINT | 0 | 4242 | 4242 | 0 | unchanged (0/false) |
| `Enable` | BIT (BOOL member) | false | true | true | false | unchanged |
| `HoldTime` | REAL | 0 | 42.5 | 42.5 | 0 | unchanged |
Every write and read returned Good (`0x00000000`); the final snapshot equals the pre-gate snapshot. Not covered:
sibling-bit preservation inside one hidden host SINT (this UDT has a single BIT member) and the libplctag
member-write path. Raw output: the session scratchpad `hw4/gate611.txt`.