docs(archreview): R2-06 live gate 5/6 + U-7 retype policy answered
- StorageRateMs bug found+fixed (PR #439); live suite 3/6 -> 5/6 - U-7: EnsureTags is a real upsert; supported-type retype ACCEPTED (Float->Double); Int1 not creatable on this histsdk (ProtocolEvidenceMissingException, Int1-only) - record the observed retype policy in docs/Historian.md (fills the placeholder)
This commit is contained in:
+46
-38
@@ -294,47 +294,55 @@ gates (R2-06 VPN, R2-08 live LDAP, R2-01 S7 blackhole) still need their infra.
|
||||
|
||||
---
|
||||
|
||||
## R2-06 live gate (T12) — attempted on the VPN, 3/6 green (2026-07-13)
|
||||
## R2-06 live gate (T12) — 5/6 green on the VPN + a real provisioning bug fixed (2026-07-13)
|
||||
|
||||
The R2-06 `Category=LiveIntegration` gate was run against a **real 0.2.0 `ZB.MOM.WW.HistorianGateway`** deployed
|
||||
The R2-06 `Category=LiveIntegration` gate ran against a **real 0.2.0 `ZB.MOM.WW.HistorianGateway`** deployed
|
||||
locally in Docker (`~/Desktop/HistorianGateway/docker`, republished at 0.2.0) pointed at the **real AVEVA
|
||||
Historian** on `wonder-sql-vd03.zmr.zimmer.com:32565` + Galaxy SQL on `wonder-app-vd03`, over the corporate VPN.
|
||||
OtOpcUa's `GatewayLiveFixture` connected h2c to the local gateway (`http://localhost:5221`,
|
||||
`HISTGW_GATEWAY_ALLOW_UNTRUSTED=true` since h2c ⇒ no cert validation; gateway `ApiKeys:Mode=Disabled`, placeholder key).
|
||||
Historian** on `wonder-sql-vd03.zmr.zimmer.com:32565` + Galaxy SQL on `wonder-app-vd03` + the `Runtime` SQL DB,
|
||||
over the corporate VPN. OtOpcUa's `GatewayLiveFixture` connected h2c to the local gateway
|
||||
(`http://localhost:5221`, `HISTGW_GATEWAY_ALLOW_UNTRUSTED=true` since h2c ⇒ no cert validation; gateway
|
||||
`ApiKeys:Mode=Disabled`, placeholder key). See `[[reference_histgw_local_deploy]]` for the full recipe.
|
||||
|
||||
**Two real deployment fixes were needed** (both in the sibling `HistorianGateway/docker/`, local-only):
|
||||
1. **DNS** — the base compose set the *short* name `Historian__Host: wonder-sql-vd03`, which does not resolve
|
||||
inside the container; overrode it to the FQDN (Galaxy/RuntimeDb already used FQDNs).
|
||||
2. **Kerberos/NTLM libs** — the historian **v6 session path** (reads + `EnsureTags`) and the SQL path authenticate
|
||||
the Windows account `Historian__UserName=NAM\dohertj2` via .NET Negotiate/GSSAPI, which `aspnet:10.0` doesn't
|
||||
ship. Without `libgssapi_krb5.so.2` every read/tag op failed with `InvalidOperationException`; adding
|
||||
`libgssapi-krb5-2 gss-ntlmssp` to `docker/Dockerfile` fixed the historian path. (The **v8 event path** —
|
||||
`SendEvent` — uses ECDH, not GSSAPI, so it worked before the fix.)
|
||||
**Three deployment fixes (sibling `HistorianGateway/docker/`, local-only):**
|
||||
1. **DNS** — base compose set the *short* `Historian__Host: wonder-sql-vd03`, which doesn't resolve in the
|
||||
container; overrode to the FQDN.
|
||||
2. **Kerberos/NTLM libs** — the historian **v6 session path** (reads + `EnsureTags`) + the SQL path authenticate
|
||||
the Windows account `NAM\dohertj2` via .NET Negotiate/GSSAPI, which `aspnet:10.0` lacks → every read/tag op
|
||||
failed `InvalidOperationException` (`Cannot load library libgssapi_krb5.so.2`). Added `libgssapi-krb5-2
|
||||
gss-ntlmssp` to `docker/Dockerfile`. (The **v8 event path**, `SendEvent`, uses ECDH — worked without it.)
|
||||
3. **RuntimeDb SQL auth** — the `Runtime` DB SQL login had to be a **SQL login** (not the Windows account, which
|
||||
a Linux container can't SQL-auth). The user supplied `wonderapp` (SQL_LOGIN with INSERT on `Runtime.dbo.History`
|
||||
+ SELECT on `dbo.Events`); wiring it made `WriteLiveValues` + SQL `ReadEvents` work.
|
||||
|
||||
**Result — 3/6 PASS:**
|
||||
- ✅ `Galaxy_tag_read_round_trip` (ReadRaw `SysTimeSec`) — historian gRPC read path live.
|
||||
- ✅ `Alarm_SendEvent_is_acked` — the alarm `SendEvent` (v8 event) path live.
|
||||
- ✅ `EnsureTags_type_change_outcome_is_observable` — passes on the *observability* contract (see caveat below).
|
||||
**🐞 Real OtOpcUa bug found + fixed (PR #439, master `666908d7`):** `GatewayTagProvisioner` built
|
||||
`HistorianTagDefinition` **without `StorageRateMs`**, so the proto `uint32` defaulted to `0`; the gateway maps it
|
||||
straight to the AVEVA SDK's `storageRateMs`, which **throws `ArgumentOutOfRangeException` ("Storage rate must be
|
||||
> 0 ms")** on `0`. So **every** deploy-time historized-tag auto-provision (`IHistorianProvisioning.EnsureTagsAsync`)
|
||||
was silently failing at the gateway (`failed=N`). Fixed by stamping `DefaultStorageRateMs=1000` (gateway
|
||||
convention) + a regression unit test + `StorageRateMs` on the live-suite inline defs. Gateway driver unit
|
||||
`103/103`.
|
||||
|
||||
**3/6 blocked (not OtOpcUa/R2-06 code defects):**
|
||||
- ❌ `Write_then_read_on_sandbox_tag`, `Alarm_SendEvent_then_ReadEvents` — the **RuntimeDb SQL path**
|
||||
(`WriteLiveValues` / SQL `ReadEvents`) must authenticate as `NAM\dohertj2`, a **WINDOWS_LOGIN** (verified via
|
||||
`sys.server_principals`). A Linux container can't SQL-auth as a Windows login (host `sqlcmd` works only because
|
||||
the go driver auto-negotiates NTLM); even with `gss-ntlmssp` present, `Encrypt=True` + explicit domain creds
|
||||
didn't connect (`SQL event read failed` / write not acked). The account is *correct* (it has INSERT on
|
||||
`Runtime.dbo.History` + SELECT on `dbo.Events`); the **auth mechanism** isn't available to a Mac container without
|
||||
a `kinit` TGT against the NAM realm. Environmental, not a code defect.
|
||||
- ❌ `EnsureTags_boolean_sandbox_provisions_as_Int1` — the gateway's `EnsureTags` returns
|
||||
`ArgumentOutOfRangeException` for **every** definition (even a fresh Float create, reproduced directly via
|
||||
`grpcurl`), *after* auth succeeds. This is a **gateway-side** issue (HistorianGateway's own live tests report
|
||||
`EnsureTags` provisioning works against `wonder-sql-vd03`, so it's env/transport/version-specific — possibly the
|
||||
`RemoteGrpc` transport not serving tag-config mutations); the gateway maps it to a bare type-name and logs no
|
||||
stack even at Debug, so the detail isn't observable without instrumenting the gateway/histsdk itself.
|
||||
**Result — 5/6 PASS** (was 3/6 before the fixes):
|
||||
- ✅ `Galaxy_tag_read_round_trip` — historian gRPC read path.
|
||||
- ✅ `Write_then_read_on_sandbox_tag` — `EnsureTags(Float)` + `WriteLiveValues` (SQL) + read-back.
|
||||
- ✅ `Alarm_SendEvent_is_acked` + ✅ `Alarm_SendEvent_then_ReadEvents` — alarm `SendEvent` + SQL `ReadEvents`.
|
||||
- ✅ `EnsureTags_type_change_outcome_is_observable` — now observes a **real** retype outcome (not a storage-rate error).
|
||||
- ❌ `EnsureTags_boolean_sandbox_provisions_as_Int1` — **Int1 (Boolean) tag creation is not supported by the
|
||||
gateway's histsdk on this historian**: `EnsureTags(Int1)` returns `ProtocolEvidenceMissingException` (the vendored
|
||||
client's "no capture evidence for this type" guard → gRPC `Unimplemented`), both fresh and as a retype target.
|
||||
A **type sweep** confirmed it is Int1-specific: **Int2/UInt2/Int4/UInt4/Float/Double all provision `success=True`;
|
||||
only Int1 fails.** This is a **gateway/histsdk type-support gap**, not an OtOpcUa defect.
|
||||
|
||||
**⚠️ U-7 retype policy — still UNDETERMINED live.** Because `EnsureTags` errors on this deployment, the retype
|
||||
probe (test 6) passes only by observing the generic `ArgumentOutOfRangeException` — it does **not** exercise a real
|
||||
Float→Int1 accept/reject. So the 06/U-7 assessment note's three hypotheses (accepted-versioned /
|
||||
accepted-retyped / rejected) remain open pending a working gateway `EnsureTags` on a real historian. The R2-06
|
||||
**code** deliverables (S-11 fail-fast + `ServerHistorianOptionsValidator`; U-7 Boolean→Int1 mapping + upsert
|
||||
semantics; C-7 doc) are all unit-covered and merged; this note records that the live *policy capture* leg is
|
||||
still outstanding, gated on the gateway `EnsureTags` fix + a SQL-auth path for the RuntimeDb tests.
|
||||
**✅ U-7 retype policy — ANSWERED (via `grpcurl` against the real historian):**
|
||||
- `EnsureTags` is a **real create-or-update upsert** — re-`EnsureTags` of an existing tag at the same type → `success`.
|
||||
- An **in-place retype between SUPPORTED types is ACCEPTED** — `Float→Double` on an existing tag returns `success`
|
||||
(of the three 06/U-7 hypotheses: **accepted-retyped**, not rejected).
|
||||
- **But the specific 0.2.0 Boolean case (Float→Int1) can't retype** — Int1 isn't a creatable type here, so a
|
||||
pre-0.2.0 **Float Boolean tag asked to become Int1 fails the provision** with `ProtocolEvidenceMissingException`
|
||||
— it is **neither silently retyped nor data-lost**; the provision just fails (and is metered `failed=N`). That is
|
||||
the practically-relevant U-7 answer for Boolean tags on this deployment.
|
||||
|
||||
The R2-06 **code** deliverables (S-11 fail-fast + `ServerHistorianOptionsValidator`; U-7 Boolean→Int1 mapping +
|
||||
upsert; C-7 doc) were already unit-covered + merged; this live gate additionally **found + fixed the StorageRateMs
|
||||
provisioning bug** and **answered the U-7 retype policy**. The one remaining red test is a documented gateway
|
||||
histsdk Int1-support gap.
|
||||
|
||||
Reference in New Issue
Block a user