# 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 `GETHI` op on the wire is **`aa/Stat/GETHI(handle, pRequestBuff)`** with `pRequestBuff = 53 67 02 00` (sig `0x6753` + version `2`) `+ uint charCount(16) + UTF-16 "HistorianVersion"` — i.e. the **named-value request**, identical to the GETRP/version shape. - Its response `pResponseBuff` is **~30 bytes**: `uint charCount(12) + UTF-16 "20,0,000,000"` (+ a `02 00 01 00` trailer). **Just the version** — not a 518-byte struct. - The post-GETHI ops in the same capture are `Hist/UpdC3` + a run of `Stat/GetSystemParameter` (`AllowOriginals`, `HistorianPartner`, `HistorianVersion`, `MaxCyclicStorageTimeout`, `RealTimeWindow`, `FutureTimeThreshold`, `AllowRenameTags`). **None carries a storage-mode value.** So the native wrapper's `EventStorageMode` is 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:** `GetHistorianInfoAsync` would add nothing over existing surface (version only) and could not report a real `EventStorageMode` — so it is intentionally **not shipped** (no hollow `Unsupported`-returning API; project discipline: don't ship misleading behavior). - **2023 R2 gRPC:** `Status.GetHistorianInfo` returns the full 518-byte `btHistorianInfo`; decode version@0 + `EventStorageMode`@514 there. Build + verify against a live 2023 R2 server. The `HistorianInfo` / `HistorianEventStorageMode` public types should land alongside that path. ## Tooling kept as RE aids - `tools/AVEVA.Historian.NativeTraceHarness` `historian-info` scenario (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).