From da4cb9271342084c9eaf851ecdd81421d7b77d28 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 12 Nov 2026 11:21:12 -0500 Subject: [PATCH] docs(otopcua-history): wire ServiceLevel correct on SDK 2 (#884 claim, #885 startup 0); vd03 still 255 until redeployed Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi --- .claude/skills/sister-project-history/otopcua.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.claude/skills/sister-project-history/otopcua.md b/.claude/skills/sister-project-history/otopcua.md index 039fe5d..70eee85 100644 --- a/.claude/skills/sister-project-history/otopcua.md +++ b/.claude/skills/sister-project-history/otopcua.md @@ -491,3 +491,11 @@ its Galaxy acks fail against mxaccessgw `2b13564e` did not apply to this box's d - **The fix:** `LegacyRsaUserNameIdentityTokenHandler`, plugged in through `UserIdentity(IUserIdentityTokenHandler)` and exposed as `OpcUaUserIdentityFactory.UserName`, always sends the legacy format under an RSA policy. That is what SDK 2 already sends for 64 bytes or less and what 1.5 clients always send. An SDK 2 server reads both formats. Client.Shared now references `Driver.OpcUaClient.Session`. - **Cross-version matrix (#782):** it now uses the 65-character key shape. The old 55-character `otua_matrix_` key had hidden the bug. The matrix adds a wrong-key case and an SDK-default negative-control case (`2ad72130`). Evidence for the fixed and mutated runs is in `e5b26f37`. The same run exposed #888: the matrix fixture's UNS folder has had no ACL placement since #808, so UNS cases are denied against master for every client. - **ScadaBridge consumer impact: none.** ScadaBridge is an SDK 1.5 client and always sent the legacy format. Generic SDK 2 tools that use the SDK's default handler are still refused by SDK 1.5 servers when the key is 65 characters. + +- **2026-11-12 master `f66b9dae` + `5e3fb422` (#884) and `3fff439b` (#885), not deployed: wire `Server.ServiceLevel` is now correct on SDK 2.0.1.** + - **The bug (#884):** SDK 2.0.1 recomputes ServiceLevel from session headroom on every session create/close and overwrites any value ≥ 200 with 255 unless a provider claims it. `SdkServiceLevelPublisher` never claimed it, so both pair nodes read 255, and a Stale 200 also read 255. + - **The fix (#884):** the publisher now claims the value through `IServerServiceLevelControl.ClaimServiceLevelControl()` and writes through the SDK's writer. + - **#885:** the server now starts at 0 (`OtOpcUaSdkServer.StartupServiceLevel`, the Down/Detached tier) instead of the SDK's 255. A restarting pair node no longer out-ranks the Primary for the ~10 s before its first redundancy snapshot. + - **Rig check (docker-dev, `3fff439b`):** all three pairs read 250/240. A rejoining node reads 0 → 240 and never goes above 240. Record: lmxopcua#801 comment 11855. + - **ScadaBridge consumer impact: none.** Its OPC UA failover is endpoint-level and doesn't read ServiceLevel. Generic clients that pick the highest ServiceLevel now get Primary preference back. + - **Deployed boxes:** DEV vd03 (`5fb4b4db`, SDK 2.0.1, single node) still advertises 255 instead of 250, and would show 255 for a Stale 200, until it's redeployed with master. QA vq03/vq04 (SDK 1.5, `b8b4c18f`) are unaffected. This was the blocker for the QA SDK 2 rollout under #801.