Code-review follow-ups: the page-coverage test now asserts every *DriverPage
declares a _jsonOpts serializer (so a new page that serialises config a
different way fails the guard, not just converter removal); clarify that 40 ==
(int)S7CpuType.S71500 in the numeric-throws test.
AdminUI driver-instance pages serialized enum config fields (S7 CpuType,
Modbus DataType/Region, AbCip PlcFamily, ...) as JSON *numbers* because each
page's _jsonOpts lacked a JsonStringEnumConverter. The driver factories,
however, deserialize into string-typed DTOs (+ lenient ParseEnum) and throw
when binding a JSON number to a string? — so an AdminUI-authored config
containing any enum field produced a blob the driver could not parse,
faulting the driver on deploy. Proven end-to-end for S7 and Modbus; latent
for AbCip/AbLegacy/TwinCAT/FOCAS/Galaxy/Historian. Only OpcUaClient was safe
(its factory + probe already carried the converter).
Add JsonStringEnumConverter to all 9 driver-instance pages' _jsonOpts and the
8 missing driver probes' _opts (factories unchanged — already string-via-
ParseEnum; strictly more permissive, also lets pages load hand-seeded
string-enum configs back into the form).
Also fix DriverProbeHandshakeE2eTests.AbCip_Green_AgainstSim to probe a real
sim tag (TestDINT) — the no-tags @raw_cpu_type fallback is rejected by the
ab_server sim with ErrorBadParam (a real ControlLogix returns ErrorNotFound,
which the probe treats as reachable; hardware-gated follow-up).
Tests: reflection guard over all driver pages' _jsonOpts (AdminUI.Tests);
factory round-trip + numeric-form-throws guards for S7 and Modbus.
Found by running the never-before-run FB-9/FB-10 live verifies.
Code-review nits: trim the seed name so the in-session dropdown label matches
the server-trimmed persisted name; add a null-selectedId test for
ResolveScriptLabel; and note in CreateNewScriptAsync that the ordering
invariant is proxied by the pure helper (AdminUI has no bUnit).
Code-review nits: SetFullName now throws on a blank reference (was silently
persisting FullName:null → silent deploy-time bind failure), and a new test
covers the alarm-typed re-pick combo (SeedDefaultAlarm over an already-edited
alarm leaves it intact).
After inline "New script" creates an SC-… id, the entry is now added
to _scripts BEFORE _form.ScriptId is set so the <InputSelect> has a
matching <option> on first render and the displayed label is correct.
Extracts VirtualTagModalHelpers.ResolveScriptLabel as a testable pure
helper (5 new unit tests in VirtualTagScriptDropdownTests).
Replace "SystemPlatform mirror tag", "Galaxy alias", and "SystemPlatform-kind" in doc-comments and
test names with neutral accurate wording ("FolderPath-scoped tag", "EquipmentId == null", etc.).
No code, logic, or test bodies changed — comments and one test method name only.
All five suppressed advisories are now resolved at baseline/resolved versions,
so every NuGetAuditSuppress is removed repo-wide:
- System.Security.Cryptography.Xml (GHSA-37gx-xxp4-5rgx / GHSA-w3x6-4m5h-cxqf)
-> fixed by the .NET 10 baseline (10.0.6)
- OPCFoundation Opc.Ua.Core (GHSA-h958-fxgg-g7w3) -> fixed at resolved 1.5.378.106
Two were still live and are now patched via direct security pins:
- OpenTelemetry.Api 1.9.0 -> 1.15.3 (GHSA-g94r-2vxg-569j) pinned in Cluster;
Runtime/ControlPlane/AdminUI + tests inherit via project reference
- Tmds.DBus.Protocol 0.20.0 -> 0.21.3 (GHSA-xrw6-gwf8-vvr9) pinned in Client.UI
Also correct the Historian sidecar runtime comments (x86 -> x64, matching the
csproj PlatformTarget). Solution audit: 0 vulnerable packages; full build clean.