Captured the native HistorianAccess.GetHistorianInfo(out HistorianInfo, out err) and decoded the wire: over 2020 WCF, GETHI is a named-value query whose only working key is "HistorianVersion" (response ~30 bytes = the version string). Probed 7 storage-mode key names -> all ok=False/err. The 518-byte HISTORIAN_INFO struct + EventStorageMode@514 is the 2023R2 HCAL-native/gRPC model (confirmed from the decompiled 2023R2 source); on 2020 the native client derives the mode outside the WCF wire. Version is already exposed (ProbeAsync/GetRuntimeParameterAsync), so no hollow GetHistorianInfoAsync is shipped (same disposition as R1.3 timezone). This completes the reachable 2020-WCF M1 read surface; remaining M1 = config writes (gated on explicit request) or gRPC/2023R2-only items. RE aids kept: harness `historian-info` scenario, Capture-HistorianInfo.ps1, decode-historian-info-capture.py, and StringHandleProbeDiagnosticTests .GETHI_CandidateInfoNames (asserts the named-value-only finding; gated). Docs: wcf-historian-info.md (new) + roadmap/matrix/wall-doc updates. 230 tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC
4.1 KiB
GetHistorianInfo over 2020 WCF — GETHI is named-value-only (HCAL R1.4)
Status: ⚠ Bounded out on 2020 WCF (2026-06-20). GetHistorianInfoAsync is not shipped:
the one field that motivates it — EventStorageMode — is not on the 2020 WCF wire. The
version field that GETHI does return over WCF is already exposed (ProbeAsync,
GetRuntimeParameterAsync("HistorianVersion")), so there is nothing new to ship here without a
2023 R2 gRPC server. This parallels R1.3 (GetServerTimeZone), which is likewise 2023R2-only.
What the capture showed
scripts/Capture-HistorianInfo.ps1 drives the native HistorianAccess.GetHistorianInfo(out HistorianInfo, out error) through the instrumented (instrument-wcf-{write,read}message)
current/aahClientManaged.dll. The native call succeeds and returns
EventStorageMode = Blocks, ServerVersion = 20,0,000,000, no error.
But the wire tells a different story (scripts/decode-historian-info-capture.py):
- The only
GETHIop on the wire isaa/Stat/GETHI(handle, pRequestBuff)withpRequestBuff = 53 67 02 00(sig0x6753+ version2)+ uint charCount(16) + UTF-16 "HistorianVersion"— i.e. the named-value request, identical to the GETRP/version shape. - Its response
pResponseBuffis ~30 bytes:uint charCount(12) + UTF-16 "20,0,000,000"(+ a02 00 01 00trailer). Just the version — not a 518-byte struct. - The post-GETHI ops in the same capture are
Hist/UpdC3+ a run ofStat/GetSystemParameter(AllowOriginals,HistorianPartner,HistorianVersion,MaxCyclicStorageTimeout,RealTimeWindow,FutureTimeThreshold,AllowRenameTags). None carries a storage-mode value. So the native wrapper'sEventStorageModeis derived by the C++ HCAL outside the WCF wire, not fetched over it.
Probe: does GETHI expose storage mode under any name?
StringHandleProbeDiagnosticTests.GETHI_CandidateInfoNames_AgainstLocalHistorian (gated on
HISTORIAN_HOST=localhost) issues GETHI for HistorianVersion plus seven storage-mode name
guesses. Result on the live 2020 server:
| GETHI parameter name | result |
|---|---|
HistorianVersion |
ok=True, respLen=32 (version) |
EventStorageMode, EventStorageType, StorageType, HistorianEventStorageMode, EventStorage, StorageMode, HistorianInfo |
ok=False, errLen=5, empty |
So GETHI on 2020 WCF is a strict named-value lookup with exactly one known-good key
(HistorianVersion). There is no storage-mode key, no full-struct request.
Why the 518-byte struct doesn't apply here
The 2023 R2 decompiled ArchestrA.HistorianAccess.GetHistorianInfo (analysis folder) allocates
a 518-byte HISTORIAN_INFO struct, pre-inits int32 @514 to -1, calls native HCAL
(vtable+648) which fills it, then reads version (UTF-16 @0) + EventStorageMode (@514:
-1=Unsupported, 0=Database, else=Blocks). That is the HCAL-native / 2023R2 gRPC
front-door model (StatusService.GetHistorianInfo returns bytes btHistorianInfo). On 2020
WCF that struct is never marshaled across the wire — only the version named-value is. The
native client's EventStorageMode therefore comes from C++-internal state the managed WCF
replay cannot observe or reproduce.
Conclusion / where it lands
- 2020 WCF:
GetHistorianInfoAsyncwould add nothing over existing surface (version only) and could not report a realEventStorageMode— so it is intentionally not shipped (no hollowUnsupported-returning API; project discipline: don't ship misleading behavior). - 2023 R2 gRPC:
Status.GetHistorianInforeturns the full 518-bytebtHistorianInfo; decode version@0 +EventStorageMode@514 there. Build + verify against a live 2023 R2 server. TheHistorianInfo/HistorianEventStorageModepublic types should land alongside that path.
Tooling kept as RE aids
tools/AVEVA.Historian.NativeTraceHarnesshistorian-infoscenario (drives the native call).scripts/Capture-HistorianInfo.ps1+scripts/decode-historian-info-capture.py.StringHandleProbeDiagnosticTests.GETHI_CandidateInfoNames_AgainstLocalHistorian(locks the named-value-only finding; gated).