fix(ab): Task 22 review r1 — release-note timing and AbLegacy regressions, probe E2E on both transports
- I1: the upgrade restart itself moves every no-key AbCip/AbLegacy driver to Native (every process start constructs drivers, incl. boot-from-cache). Docs + CLAUDE.md now say so and tell operators to set "transport": "Libplctag" BEFORE upgrading (older builds ignore the unknown key). - I2: AbLegacy release note leads with the status-bit write refusal (T4:0.DN, C5:0.CU, R6:0.EN, ...) on defaulted SLC/MicroLogix drivers and the fallback. The real client status is BadCommunicationError, not BadNotSupported (the driver's write catch-all maps the runtime's AbTransportException like any transport failure, as #571 does for PLC-5), with handle eviction and Degraded health; pinned by a driver-level test (no 0xAA write on the wire, with a positive control). ST string byte order stated as unverified. Also corrects the docs' "T4:0/DN" examples: the driver's address grammar is "T4:0.DN" ("/DN" is a malformed address). - I3: DriverProbeHandshakeE2eTests' two AbCip probe tests are a [Theory] over Native and Libplctag. Run against ab_server controllogix: all 4 rows pass with identical exact messages. - M1: documented (docs + resolver XML doc): the AdminUI merges only the probed device, so a mixed-family defaulted AbLegacy driver can probe Native while running Libplctag. - M2: factory ParseEnum rejects undefined integer strings ("7") via Enum.IsDefined (both drivers). - M3: AbCip driver-level bad value reads "AB CIP config in '<id>' has unknown Transport ..."; the named constant is gone (tagName: null now means driver-level). - M4: the explicit-Native limited-family Warning is once per instance, not per (re)init. - Nit: EffectiveTransport docs note that injected factories bypass it. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -97,7 +97,8 @@ The driver has two interchangeable wire transports, selected by one `DriverConfi
|
||||
- An absent key means "use the default". It is resolved in one place, `AbCipTransportResolver`, which the
|
||||
driver, the Test Connect probe and the CLI all go through. An explicit value always wins.
|
||||
- A bad value fails like a bad `PlcFamily`; the Test Connect probe reports "Config JSON is invalid".
|
||||
- A change takes effect when the driver instance is **recreated**. A deploy that changes `DriverConfig`
|
||||
- A change takes effect when the driver instance is **constructed**: on every process start (so the upgrade
|
||||
restart moves no-key drivers to Native — see the release note) and when a deploy that changes `DriverConfig`
|
||||
does this (`DriverHostActor` respawns the child, #516). `ReinitializeAsync` alone keeps the transport
|
||||
it was constructed with.
|
||||
- AdminUI: the **Transport** dropdown in the advanced section of the AbCip driver form ("Default (Native)" /
|
||||
@@ -120,8 +121,11 @@ The driver has two interchangeable wire transports, selected by one `DriverConfi
|
||||
authored type; see [Native transport behaviour](#native-transport-behaviour).
|
||||
- **To fall back**, set `"transport": "Libplctag"` in the driver config (or pick "libplctag (fallback)" in
|
||||
the AdminUI dropdown).
|
||||
- **When it takes effect:** a change of transport — including this default flip for an existing driver with
|
||||
no key — takes effect when a deploy recreates the driver instance, not on `ReinitializeAsync`.
|
||||
- ⚠️ **When it takes effect: the upgrade restart itself.** Every process start constructs the drivers
|
||||
(including boot-from-cache on a driver-only node), so **every driver with no `transport` key moves to Native
|
||||
the moment the upgraded node starts** — no deploy is needed. To keep a driver on libplctag, add
|
||||
`"transport": "Libplctag"` and deploy it **before upgrading**: older builds ignore the unknown key. After the
|
||||
upgrade, a transport change takes effect when a deploy recreates the driver (not on `ReinitializeAsync`).
|
||||
- **Evidence, and its limits:** AbCip **reads** (plus browse and templates) were proven on a production
|
||||
CompactLogix 5069-L320ERS2 (**Z-35162**, read-only, 2026-10-08; see
|
||||
[gate results](../plans/2026-10-07-native-ab-transport-gate-results.md) §Real press). AbCip **writes** are
|
||||
@@ -153,7 +157,7 @@ The driver has two interchangeable wire transports, selected by one `DriverConfi
|
||||
writes are gated on a mismatch too.
|
||||
- Malformed tag names put the device into backoff, as under libplctag (#570). STRING capacity includes the
|
||||
alignment pad (84, not 82) (#570).
|
||||
- Status-bit sub-element writes (e.g. `T4:0/DN`) are Unsupported natively (they would clobber the control
|
||||
- Status-bit sub-element writes (e.g. `T4:0.DN`) are Unsupported natively (they would clobber the control
|
||||
word); nothing goes on the wire. Sub-element arrays are Unsupported natively.
|
||||
|
||||
## Known gaps
|
||||
|
||||
@@ -108,9 +108,17 @@ PCCC-over-EtherNet/IP client (`Driver.Ab.Transport`).
|
||||
the CLI): an absent key resolves to `Native`, **unless any configured device has `PlcFamily` `Plc5` or
|
||||
`LogixPccc`** — then the whole driver resolves to `Libplctag`, because the transport is chosen once per driver,
|
||||
not per device. An explicit value always wins: explicit `Native` with a PLC-5 / `LogixPccc` device is allowed
|
||||
(an operator choice) and logs one Warning at init naming the limitation.
|
||||
(an operator choice) and logs one Warning per driver instance naming the limitation.
|
||||
|
||||
A change takes effect when the driver instance is recreated (a deploy that changes `DriverConfig`). The
|
||||
⚠️ **Test Connect in a mixed-family driver can disagree with the runtime.** The AdminUI probe merges the
|
||||
driver config with **only the device being probed**, so in a defaulted driver holding an SLC 500 and a PLC-5,
|
||||
Test Connect on the SLC device resolves `Native` while the deployed driver runs every device on `Libplctag`.
|
||||
SLC 500 works on both stacks, so this is cosmetic; the reverse (probe on libplctag, driver on native) cannot
|
||||
happen. Set `transport` explicitly to make them agree.
|
||||
|
||||
A change takes effect when the driver instance is constructed: on a deploy that changes `DriverConfig`
|
||||
(which recreates it) **and on every process start**, including the restart that installs this build (see the
|
||||
release note). The
|
||||
AdminUI form's **Transport** dropdown offers "Default (Native; libplctag for PLC-5 / LogixPccc)" (omits the
|
||||
key on save), "Native (managed)" and "libplctag (fallback)". The driver logs
|
||||
`transport=<effective> (default|configured)` on every init, e.g. `transport=Libplctag (default; PLC-5/LogixPccc
|
||||
@@ -124,6 +132,16 @@ Native routing: SLC500/MicroLogix/PLC-5 are direct; `logixpccc` uses Unconnected
|
||||
|
||||
### Release note — native is the default (Task 22)
|
||||
|
||||
- ⚠️ **Status-bit writes are refused on the default.** An SLC 500 / MicroLogix driver on the native default
|
||||
**refuses writes to status-bit sub-elements** — `T4:0.DN`, `T4:0.TT`, `T4:0.EN`, `C5:0.CU`, `C5:0.DN`,
|
||||
`R6:0.EN`, and the rest. The client sees **`BadCommunicationError`** (not `BadNotSupported`: the driver's
|
||||
write path maps the refusal like any transport failure, as for the PLC-5 refusal in #571), the tag's handle
|
||||
is evicted, and driver health goes `Degraded` with "Writes to a status-bit sub-element … are not supported by
|
||||
the native transport". **Nothing is written to the PLC.** libplctag performed a masked bit write here, so an
|
||||
authored writable status-bit tag that worked before the upgrade fails after it. This is deliberate: a native
|
||||
read-modify-write of the control word would race the PLC updating TT/DN and could clobber EN/TT/DN, and such
|
||||
writes are rare. **Drivers that need them must set `"transport": "Libplctag"`.** Reads of status bits are
|
||||
unaffected. Word sub-elements (`T4:0.PRE`, `T4:0.ACC`, `R6:0.LEN`, `R6:0.POS`) still write natively.
|
||||
- **The native managed transport is now the default** for SLC 500 and MicroLogix. A driver config with no
|
||||
`transport` key runs `Native`; libplctag remains available as the fallback.
|
||||
- **Exclusion:** a defaulted driver with **any PLC-5 or `LogixPccc` device stays on libplctag**. Native PLC-5
|
||||
@@ -131,9 +149,14 @@ Native routing: SLC500/MicroLogix/PLC-5 are direct; `logixpccc` uses Unconnected
|
||||
there, with a Warning at init.
|
||||
- ⚠️ **Client-visible:** native reports **`BadTypeMismatch`** for a mis-authored same-width type, where
|
||||
libplctag returned Good garbage (see [AbCip.md §Native transport behaviour](AbCip.md#native-transport-behaviour)).
|
||||
- **ST (string) files:** the native ST file byte order is **unverified** (no capture), so string values read or
|
||||
written natively may be byte-swapped. Drivers with ST tags whose values matter should fall back.
|
||||
- **To fall back**, set `"transport": "Libplctag"` in the driver config.
|
||||
- **When it takes effect:** when a deploy recreates the driver instance (not on `ReinitializeAsync`). An existing
|
||||
driver with no key moves to Native on its next recreate.
|
||||
- ⚠️ **When it takes effect: the upgrade restart itself.** Every process start constructs the drivers
|
||||
(including boot-from-cache on a driver-only node), so **every driver with no `transport` key moves to
|
||||
Native the moment the upgraded node starts** — no deploy is needed. To keep a driver on libplctag, add
|
||||
`"transport": "Libplctag"` and deploy it **before upgrading**: older builds ignore the unknown key. After the
|
||||
upgrade, a transport change takes effect when a deploy recreates the driver (not on `ReinitializeAsync`).
|
||||
- **Evidence, and its limits:** all of AbLegacy is **simulator-proven only** (`ab_server`). No real SLC,
|
||||
MicroLogix or PLC-5 has been exercised. (The real-press gate, Z-35162 2026-10-08, covered AbCip reads only.)
|
||||
|
||||
@@ -144,7 +167,7 @@ Native routing: SLC500/MicroLogix/PLC-5 are direct; `logixpccc` uses Unconnected
|
||||
- **PLC-5 native is N-file reads only.** Every other file type and all PLC-5 writes are refused, currently
|
||||
surfacing as `BadCommunicationError` rather than `BadNotSupported` (#571). The default excludes PLC-5 and
|
||||
`logixpccc` (they resolve to libplctag unless `Native` is set explicitly).
|
||||
- Status-bit sub-element writes (e.g. `T4:0/DN`, `C5:0/DN`) are Unsupported natively (they would clobber the
|
||||
- Status-bit sub-element writes (e.g. `T4:0.DN`, `C5:0.DN`) are Unsupported natively (they would clobber the
|
||||
control word); nothing goes on the wire. Sub-element arrays are Unsupported natively. L-file bit indexes
|
||||
above 15 are allowed.
|
||||
- **ST (string) file layout is uncaptured**, so the string byte order is unverified natively.
|
||||
|
||||
Reference in New Issue
Block a user