From 2246fdd395277224b9d0cdf414681dc0a9966727 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 20 Jun 2026 15:22:53 -0400 Subject: [PATCH] docs: reclassify M1a R1.1/R1.3 as blocked on 2020 WCF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live-probed both against the local Historian 2020 (WCF): - R1.3 GetServerTimeZoneAsync: Status.GetSystemTimeZoneName returns rc=0 with an empty value under a real authenticated handle — a client-side stub in the GetServerTime family. gRPC/2023R2-only. Reverted the implementation. - R1.1 ExecuteSqlCommandAsync: Retrieval.ExeC returns native error type 4 / code 51 (InvalidParameter); the contract-3 string-handle ops require an unmapped native session/filter registration step (the StartTagQuery wall). Adds an M1a re-classification note steering future work toward proven uint-handle / already-wired ops (R1.4 GETHI next) over string-handle ops. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/plans/hcal-roadmap.md | 18 ++++++++++++++++-- .../wcf-status-localhost.md | 16 ++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/docs/plans/hcal-roadmap.md b/docs/plans/hcal-roadmap.md index 53432b3..9ac0edc 100644 --- a/docs/plans/hcal-roadmap.md +++ b/docs/plans/hcal-roadmap.md @@ -24,6 +24,20 @@ HCAL replacement, built on the **2023 R2 gRPC transport**. Derived from > golden-byte/unit-tested here but **cannot be live-verified** without an actual 2023 R2 server. > Treat gRPC ops as unverified until then; the byte payloads remain the proven 2020 protocol. +> šŸ”¬ **M1a re-classification (2026-06-20).** Two "trivial" items were live-probed against the +> 2020 WCF server and found **not deliverable here**, both for evidence-backed reasons: +> - **R1.3 `GetServerTimeZoneAsync`** — `Status.GetSystemTimeZoneName` is a client-side *stub* +> on 2020 (rc=0, empty value), same family as `GetServerTime`. gRPC/2023R2-only. +> - **R1.1 `ExecuteSqlCommandAsync`** — `ExeC` returns native error 51 (InvalidParameter); +> the contract-3 string-handle ops require an unmapped native session/filter registration +> step (the `StartTagQuery` wall). +> +> Takeaway: the M1a "cheap surface" is *cheap only on the 2023 R2 gRPC front door*. On 2020 WCF, +> the genuinely reachable next items are those that reuse a **proven uint-handle Retrieval op or +> an already-wired call** — e.g. **R1.4 `GetHistorianInfoAsync`** (GETHI is already invoked in +> the event chain) and the extended/localized-property reads (R1.5/R1.6) that ride +> `GetTagInfo*`-style ops. Prefer those before any string-handle (`ExeC`/`QTB`/`QTG`) op. + ## Guiding principles 1. **gRPC-first.** New ops go on the `RemoteGrpc` transport (clean protobuf envelope); @@ -68,9 +82,9 @@ read/browse/status surface is Windows-free and the gRPC stack is the default pat ### 1a. Trivial (XS–S each, no new payload format) | ID | Capability | gRPC op | Notes | |---|---|---|---| -| R1.1 | `ExecuteSqlCommandAsync` | `Retrieval.ExecuteSqlCommand` | string in → `iRetValue` + status; thin | +| ~~R1.1~~ | ~~`ExecuteSqlCommandAsync`~~ | `Retrieval.ExecuteSqlCommand` | ⚠ **Blocked on 2020 WCF.** Live-probed 2026-06-20: `ExeC` returns native error type 4 / code **51 (InvalidParameter)** for every handle variant — same unmapped *native session/filter registration* prerequisite that blocks `StartTagQuery`/`QueryTag` (see `implementation-status.md` lines ~982, ~1404). Needs that registration RE'd, or a 2023 R2 gRPC server. Do not wire via guessed calls. | | R1.2 | `GetRuntimeParameterAsync` | `Status.GetRuntimeParameter` | mirror `GetSystemParameter` | -| R1.3 | `GetServerTimeZoneAsync` | `Status.GetSystemTimeZoneName` | string out | +| ~~R1.3~~ | ~~`GetServerTimeZoneAsync`~~ | `Status.GetSystemTimeZoneName` | ⚠ **gRPC/2023R2-only.** Verified 2026-06-20: over **2020 WCF** this op is a stub (rc=0, empty value) in the `GetServerTime` family — not shippable here. Build+verify only against a live 2023 R2 server. See `docs/reverse-engineering/wcf-status-localhost.md`. | ### 1b. Bounded (decode one `bytes` payload; S–M each) | ID | Capability | gRPC op | Payload to decode | Depends | diff --git a/docs/reverse-engineering/wcf-status-localhost.md b/docs/reverse-engineering/wcf-status-localhost.md index f2a4852..d0bd776 100644 --- a/docs/reverse-engineering/wcf-status-localhost.md +++ b/docs/reverse-engineering/wcf-status-localhost.md @@ -26,9 +26,25 @@ Observed sanitized localhost results: - `GetSystemParameter(handle: 0, "Version")` returns `false` with no error buffer. +Re-tested 2026-06-20 with a **real authenticated client handle** (full Open2 auth +chain), not `handle: 0`: + +- `GetSystemParameter(handle, "HistorianVersion")` → real version string (works; + shipped as `GetSystemParameterAsync`). +- `GetSystemTimeZoneName(handle)` → return code `0x00000000` (success) but an + **empty value string**. Same channel/handle that makes `GetSystemParameter` + return real data, so this is the op's own behavior, not an auth/marshalling + gap. `GetSystemTimeZoneName` is a member of the `GetServerTime` stub family: + the 2020 WCF path returns success without producing a value (the native client + computes the zone locally). It only becomes a real round-trip on the 2023 R2 + gRPC front door (`Status.GetSystemTimeZoneName`), which is absent on this box. + Interpretation: - `Stat` endpoint routing is confirmed, but status operations that require a real client handle are not usable until managed session open is solved. - `GetServerTime` should not be promoted into the public SDK as a real server time call from this WCF path; native evidence shows it is a no-op stub here. +- **`GetServerTimeZoneAsync` (roadmap R1.3) is NOT a trivial WCF op on 2020** — it + is a stub returning empty. Do not ship it over the 2020 WCF transport. Deliver + it only against a live 2023 R2 gRPC server. Reclassified in `docs/plans/hcal-roadmap.md`.