docs: record OPC UA 2.0 migration baseline and decisions
This commit is contained in:
@@ -62,3 +62,6 @@ lib/
|
||||
|
||||
# Subagent-driven-development git worktrees
|
||||
.worktrees/
|
||||
|
||||
# OPC UA SDK upgrade verification artifacts
|
||||
/artifacts/opcua2/
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
# OPC UA SDK 2.0 execution evidence
|
||||
|
||||
Execution started 2026-11-10 for [#782](https://gitea.dohertylan.com/dohertj2/lmxopcua/issues/782), following the reviewed [plan](2026-11-10-opcua-sdk-2-upgrade.md). This records evidence and decisions; Gitea remains the status system.
|
||||
|
||||
## Baseline and authority
|
||||
|
||||
- Baseline `83ed880e4471344deaf008da9bd028c7e170bdc7` equals fetched `origin/master`; original checkout clean. Dedicated managed worktree, branch `codex/opcua-sdk-2`.
|
||||
- Target remains exact stable SDK `2.0.1`, upstream `07e62f72500cc0923a2bab940653c8c1116fa286`. Tagged source and restored assemblies control API decisions.
|
||||
- Baseline packages are already `1.5.378.182`, not the plan preparation checkout's `.106`. #751 reflection helper exists. AggregateManager application configuration override already exists; preserve it.
|
||||
- #782 previously parked the major upgrade; the user's current explicit execution instruction supersedes that scheduling decision. No deployment authorization overrides the Wonder-box remote-execution hold.
|
||||
- Environment: macOS 26.5 arm64, .NET SDK 10.0.403, runtime 10.0.14; global.json 10.0.100 latestFeature accepts this SDK. Windows/Linux runtime, real ScadaBridge, AVEVA/backend and two-hour soak gates need actual execution evidence before release.
|
||||
- Sources: nuget.org (`*` mapping), tracked `nuget-packages` MxGateway feed, Gitea family feed per NuGet.config. No source changes.
|
||||
- Baseline restore succeeded; Release whole-solution build succeeded with **0 warnings, 0 errors** (18.44 s). Logs: ignored `artifacts/opcua2/83ed880e/baseline/`. Targeted baseline tests ran serially with `AKKA_TEST_TIMEFACTOR=3`, fresh per-project TRX and nonzero execution guards.
|
||||
|
||||
## SDK-consuming projects
|
||||
|
||||
Direct SDK references:
|
||||
|
||||
- `src/Client/ZB.MOM.WW.OtOpcUa.Client.Shared/ZB.MOM.WW.OtOpcUa.Client.Shared.csproj`
|
||||
- `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.csproj`
|
||||
- `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser.csproj`
|
||||
- `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Session/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Session.csproj`
|
||||
- `src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/ZB.MOM.WW.OtOpcUa.OpcUaServer.csproj`
|
||||
- `tests/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests.csproj`
|
||||
- `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.IntegrationTests/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.IntegrationTests.csproj`
|
||||
- `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Sql.Common.Tests/ZB.MOM.WW.OtOpcUa.Driver.Historian.Sql.Common.Tests.csproj`
|
||||
- `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.IntegrationTests.csproj`
|
||||
- `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.Tests/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.Tests.csproj`
|
||||
- `tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests.csproj`
|
||||
|
||||
Transitive SDK consumers (restored baseline graph):
|
||||
|
||||
- `src/Client/ZB.MOM.WW.OtOpcUa.Client.CLI/ZB.MOM.WW.OtOpcUa.Client.CLI.csproj`
|
||||
- `src/Client/ZB.MOM.WW.OtOpcUa.Client.UI/ZB.MOM.WW.OtOpcUa.Client.UI.csproj`
|
||||
- `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.csproj`
|
||||
- `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.csproj`
|
||||
- `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer/ZB.MOM.WW.OtOpcUa.Driver.Historian.SqlServer.csproj`
|
||||
- `src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ZB.MOM.WW.OtOpcUa.AdminUI.csproj`
|
||||
- `src/Server/ZB.MOM.WW.OtOpcUa.Host/ZB.MOM.WW.OtOpcUa.Host.csproj`
|
||||
- `src/Server/ZB.MOM.WW.OtOpcUa.Runtime/ZB.MOM.WW.OtOpcUa.Runtime.csproj`
|
||||
- `tests/Client/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests.csproj`
|
||||
- `tests/Client/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests.csproj`
|
||||
- `tests/Client/ZB.MOM.WW.OtOpcUa.Client.UI.Tests/ZB.MOM.WW.OtOpcUa.Client.UI.Tests.csproj`
|
||||
- `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests.csproj`
|
||||
- `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.Tests/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.Tests.csproj`
|
||||
- `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser.IntegrationTests/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser.IntegrationTests.csproj`
|
||||
- `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser.Tests/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser.Tests.csproj`
|
||||
- `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.IntegrationTests/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.IntegrationTests.csproj`
|
||||
- `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests.csproj`
|
||||
- `tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/ZB.MOM.WW.OtOpcUa.AdminUI.Tests.csproj`
|
||||
- `tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests.csproj`
|
||||
- `tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests.csproj`
|
||||
- `tests/Server/ZB.MOM.WW.OtOpcUa.Host.Tests/ZB.MOM.WW.OtOpcUa.Host.Tests.csproj`
|
||||
- `tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.csproj`
|
||||
- `tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/ZB.MOM.WW.OtOpcUa.Runtime.Tests.csproj`
|
||||
|
||||
## Boundary decisions
|
||||
|
||||
Preserve existing CLR scalar widths, strings/nulls, Guid, UTC DateTime, byte[] and typed one-dimensional arrays at existing outward adapter/domain boundaries. Explicitly normalize ByteString/ArrayOf; no accidental SDK values in Core or driver Contracts. Copy mutable buffers when retained. Keep byte-array versus ByteString wire distinction at encoding sites. No new matrix capability. Existing Client.Shared SDK-facing DataValue/NodeId/Variant DTOs remain SDK-facing; this upgrade does not rewrite their public API. NodeIds bind namespace URI and identifier, including opaque identifiers.
|
||||
|
||||
Existing write conversions are part of the deployed contract: scalar Double→Float leniency and checked numeric-array conversions remain permitted where existing tests require them; Modbus/S7 refuse scalar-shaped array writes while pass-through drivers preserve their existing behavior. Reject unsupported rank/index range and unsafe conversions before driver I/O. Task 5's shorthand “wrong type rejected” means invalid **under this existing contract**, not blanket exact-type rejection. SDK stricter prevalidation must be reconciled with positive wire tests, without widening permissions.
|
||||
|
||||
No optional ManagedSession/DI/AOT/cluster redesign, trust relaxation, silent warning suppression, or SDK version substitution. All integration harness changes remain coordinator-owned; three implementation lanes start only after G0/G1 and frozen contract.
|
||||
|
||||
## Gates
|
||||
|
||||
- G0 baseline/design: accepted for migration, with corrections and external/trust-matrix gaps recorded below.
|
||||
- G1 restored 2.0 graph / break inventory: pending.
|
||||
- G2 compilation convergence: pending.
|
||||
- G3 behavioral/security/interoperability: pending.
|
||||
- G4 lifecycle/performance/publish: pending.
|
||||
- Astra security/ownership and release reviews: pending.
|
||||
|
||||
No upgraded artifact is approved for release.
|
||||
|
||||
## G0 design review corrections
|
||||
|
||||
Astra (`gpt-6-astra`, high) conditionally approved the design. Both actionable corrections are accepted:
|
||||
|
||||
1. Preserve scalar numeric leniency, checked numeric-array conversion (`int[]`→`short[]`) and pass-through scalar-shaped array dispatch. Positive `ArrayWriteWireTests` remain the compatibility oracle; never change expected statuses simply to accept SDK prevalidation regressions.
|
||||
2. Peer evidence feeds `BoundedApiKeyStore` per-IP miss budgets, not a CIDR admission policy. Unknown peer keeps the process-wide budget fallback and valid-key admission. CIDR-only cases in the original plan are inapplicable to this baseline. Replace the reflection helper and preserve `ApiKeyMissBudgetPerEndpointTests`; `RemoteEndpointResolutionTests` does not exist.
|
||||
|
||||
Also preserve native alarm `ApiKeyId` dispatch/preflight, #763/#764 stale BadNoSubscription suppression and idle-session behavior (`OpcUaClientStaleNoSubscriptionTests`), typed event-history fields/statuses, xUnit v3 3.2.2 conventions and CI floor 12,000. Full G0 remains conditional on baseline test accounting.
|
||||
|
||||
### Frozen lane conversion recipe
|
||||
|
||||
Use exact target `VariantHelper.TryCastFrom(value, out Variant)` (no reflection fallback) only for already-supported built-ins; reject unsupported values with the existing owning operation status. Scalar and array wrappers must be detached from mutable caller buffers before retention. Use explicit typed Variant factories where the type is statically known. `AsBoxedObject(Variant.BoxingBehavior.Legacy)` normalizes ArrayOf to CLR arrays, but **does not normalize packed ByteString or DateTimeUtc scalars** in tagged 2.0.1: convert those explicitly to byte[] / UTC DateTime and map Uuid to Guid where existing domain payloads require it. Never claim default AsBoxedObject preserves CLR payloads. Preserve null versus empty wrapper semantics. Test mutation after publication/readback. Byte[] wire rank must match the existing node operation (Byte array versus scalar ByteString), not a global inference.
|
||||
|
||||
Existing Client.Shared ValueConverter text parsing policy is unchanged; do not expand supported text types. Domain snapshots have no picosecond fields; preserve SDK metadata on SDK-facing values but do not expand the domain snapshot schema. No new matrix flattening or materialization support. Preserve scalar-shaped pass-through upstream arrays already supported.
|
||||
|
||||
Baseline host and CLI artifacts published using existing Release outputs; 934 files hashed in `artifacts/opcua2/83ed880e/baseline/artifact-sha256.json`. They are local verification artifacts, not deployment packages or published releases.
|
||||
|
||||
## Baseline verification (G0)
|
||||
|
||||
| Project | Passed/executed | Skipped |
|
||||
|---|---:|---:|
|
||||
| ZB.MOM.WW.OtOpcUa.Client.CLI.Tests | 168/168 | 0 |
|
||||
| ZB.MOM.WW.OtOpcUa.Client.Shared.Tests | 240/240 | 0 |
|
||||
| ZB.MOM.WW.OtOpcUa.Client.UI.Tests | 130/130 | 0 |
|
||||
| ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser.IntegrationTests | 5/5 | 0 |
|
||||
| ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser.Tests | 19/19 | 0 |
|
||||
| ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.IntegrationTests | 5/5 | 0 |
|
||||
| ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests | 298/298 | 0 |
|
||||
| ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests | 133/133 | 0 |
|
||||
| ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests | 1027/1027 | 1 |
|
||||
|
||||
**2025 baseline tests executed, zero failures.** All nine owning test projects passed nonzero execution guards. Server integration total is 133 (the earlier issue comment described 132). Skip-guard fixture tests 11/11 pass. The simulator is pinned `mcr.microsoft.com/iotedge/opc-plc:2.14.10`, task-owned container `otopcua-sdk2-baseline-plc` at reserved `opc.tcp://localhost:50000`; autoaccept/None is an interoperability baseline only, not trusted-channel proof. Existing server security tests cover profile configuration; a new explicit trusted secure-channel/certificate rejection matrix remains a G3 obligation. Windows/Linux runtime and actual ScadaBridge/backend evidence remain pending, not inferred from this macOS baseline.
|
||||
|
||||
G0 is accepted for migration with these explicitly accounted external/trust-matrix gaps and Astra's two design corrections adopted above. No baseline failure is hidden or attributed to SDK 2.0.
|
||||
Reference in New Issue
Block a user