# GetHistorianInfo over 2020 WCF — GETHI is named-value-only (HCAL R1.4) **Status: ⛔ Bounded out on BOTH 2020 WCF and 2023 R2 gRPC (2026-06-20; gRPC live-confirmed 2026-06-21).** `GetHistorianInfoAsync` is **not shipped on any transport**: the one field that motivates it — `EventStorageMode` — is **not on the wire** on either transport (it lives only in the C++ HCAL's in-memory 518-byte struct, filled via a native vtable+648 call — see the §gRPC conclusion below). The version field GETHI *does* return is already exposed (`ProbeAsync`, `GetRuntimeParameterAsync("HistorianVersion")`), so there is nothing new to ship. Note: R1.3 (`GetServerTimeZone`) — once paired with this as "2023R2-only" — **diverged**: it returns a real value over gRPC and **shipped** 2026-06-21 (`GetServerTimeZoneAsync`); R1.4 did not. ## 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 — LIVE-PROBED 2026-06-21, also bounded out.** The earlier expectation that `Status.GetHistorianInfo` returns the full 518-byte `btHistorianInfo` over gRPC was **wrong**. On the real 2023 R2 server (History iface 12), the gRPC `GetHistorianInfo` is the **same named-value query** as 2020 WCF: only `HistorianVersion` resolves (→ `"23,1,000,000"` + `02 00 01 00` trailer); `EventStorageMode` and seven name variants return `success=false` on **both** `GetHistorianInfo` and `GetSystemParameter`. The 518-byte struct is **not on the gRPC wire** — the 2023 R2 decompile confirms managed `HistorianAccess.GetHistorianInfo` fills it via a **native vtable+648 HCAL call** (`IClientCommon*` + offset 648), not the gRPC op, so `EventStorageMode` is derived inside the C++ HCAL outside the wire on gRPC exactly as on WCF. **Conclusion: `GetHistorianInfoAsync` is not shipped on any transport** (the only wire-reachable field, version, is already exposed). No `HistorianInfo` / `HistorianEventStorageMode` public type was added. Probe: the (now-deleted) `GrpcStatusInfoProbeTests`; raw dump under `artifacts/reverse-engineering/grpc-status-info-probe/` (gitignored). ## 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).