AvevaGatewayHistoryLiveGateTests boots the server in-process, wires the production Gateway backend (HistorianBackendRegistry -> GatewayHistorianDataSource) to a real HistorianGateway and drives HistoryRead over a real SDK session: raw (all, paged, reverse, bounds), modified, the ten served aggregates and seven refused ones, AtTime, events (all, 1-event pages, reverse), a missing tag, HistoryServerCapabilities and node metadata, and a HistoryUpdate that must be refused (sandbox-bound node only). Every wire answer is compared with the backend's direct answer; the run is dumped as JSON for cross-SDK and SQL comparison. Skips unless HISTGW_GATEWAY_ENDPOINT and HISTGW_GATEWAY_APIKEY are set; read-only by construction. scripts/validation/aveva-history-801: run/compare instructions, the SDK 1.5.378 baseline port patch (API spelling only), and the diff / SQL / aggregate / histgw-cli comparison scripts. Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi
#801 real-AVEVA history gate (SDK 2.0.1 vs 1.5.378.182)
Harness: tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/AvevaGatewayHistoryLiveGateTests.cs.
It boots the OtOpcUa server in-process (ServerEventRig), wires the production Gateway backend
(HistorianBackendRegistry → GatewayHistorianDataSource) to a real HistorianGateway, and drives HistoryRead /
HistoryUpdate over a real SDK client session. It skips unless HISTGW_GATEWAY_ENDPOINT and HISTGW_GATEWAY_APIKEY
are set. It is read-only: the Gateway backend has no updater, and the only HistoryUpdate goes to a node bound to
HISTGW_WRITE_SANDBOX_TAG and is refused by the server before any backend call.
Record of the 2026-11-12 run: docs/plans/evidence/2026-11-10-opcua2/aveva-history-801.md.
Run (SDK 2, this tree)
export HISTGW_GATEWAY_ENDPOINT=http://wonder-app-vd03.zmr.zimmer.com:5221
export HISTGW_GATEWAY_APIKEY="$(cat /path/to/key-file)" # never on the command line
export HISTGW_WRITE_SANDBOX_TAG=HistGW.LiveTest.Sandbox
export OTOPCUA_AVEVA_GATE_OUT=/tmp/aveva-gate OTOPCUA_AVEVA_GATE_LABEL=sdk2-$(git rev-parse --short HEAD)
dotnet test tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests -c Release \
--filter "FullyQualifiedName~AvevaGatewayHistoryLiveGate"
Baseline (SDK 1.5.378.182)
git worktree add --detach ../otopcua-sdk1 efb9197a # master's first parent before the SDK 2 merge b36e688f
cp tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/AvevaGatewayHistoryLiveGateTests.cs \
../otopcua-sdk1/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/
(cd ../otopcua-sdk1 && patch -p1 < "$OLDPWD/scripts/validation/aveva-history-801/sdk1-baseline-port.patch")
# then the same dotnet test command in ../otopcua-sdk1 with OTOPCUA_AVEVA_GATE_LABEL=sdk1-efb9197a
sdk1-baseline-port.patch changes only SDK API spelling: collections in place of ArrayOf, byte[] in place of ByteString,
DataValue.Value in place of ClrValue(). The queries, windows and comparisons are unchanged.
Compare
python3 -I diff_runs.py $OUT/aveva-gate-sdk2-*.json $OUT/aveva-gate-sdk1-efb9197a.json # every case, row and event
python3 -I sql_raw_check.py $OUT/aveva-gate-sdk2-*.json # raw rows vs Runtime.dbo.History (Full, UTC); needs
# HISTORIAN_SQL_USER / HISTORIAN_SQL_PASSWORD, read-only
python3 -I aggregate_recompute.py $OUT/aveva-gate-sdk2-*.json # simple aggregates recomputed from the raw rows
python3 -I hgcli_raw_check.py $OUT/aveva-gate-sdk2-*.json $OUT # vs histgw-cli read-raw output (hgcli-<tag>-<date>.jsonl)