docs(grpc): reflect newly-tooled config ops in the transport matrix
- GetRuntimeParameter / GetTagExtendedProperties now live-verified over gRPC - ExecuteSqlCommand marked server-walled (new legend state) - tag-config writes marked sandbox-gated (new legend state) - document the HISTORIAN_GRPC_WRITE_SANDBOX_TAG live-test gate - rewrite the matrix summary to reflect what was learned tooling the config ops Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC
This commit is contained in:
@@ -66,8 +66,11 @@ Open2 buffers and SSPI tokens on both — on gRPC they simply ride inside protob
|
||||
`bytes` fields — so reads are at parity. The surfaces diverge at the edges.
|
||||
|
||||
Legend: ✅ tooled + live-verified · ⚠️ tooled, partial/synthesized ·
|
||||
🔌 **the gRPC server exposes the RPC (recovered in `Grpc/Protos/*.proto`) but the
|
||||
SDK doesn't drive it yet** — untooled/uncaptured, *not* a protocol gap ·
|
||||
🧪 tooled + routed but **sandbox-gated** (mutates server state, not yet run
|
||||
destructively against a live box) · 🔌 **the gRPC server exposes the RPC
|
||||
(recovered in `Grpc/Protos/*.proto`) but the SDK doesn't drive it yet** —
|
||||
untooled/uncaptured, *not* a protocol gap · ⛔ tooled but **server-walled** (the
|
||||
request rides the RPC but the server faults on an unmet precondition) ·
|
||||
❌ unavailable on that transport.
|
||||
|
||||
| Operation | WCF | gRPC | Notes |
|
||||
@@ -82,27 +85,32 @@ SDK doesn't drive it yet** — untooled/uncaptured, *not* a protocol gap ·
|
||||
| `AddHistoricalValuesAsync` | ❌ | ✅ | historical/backfill writes ride `HistoryService.AddStreamValues`; non-gRPC throws `ProtocolEvidenceMissingException` |
|
||||
| `GetServerTimeZoneAsync` | ❌ | ✅ | 2020 `GetSystemTimeZoneName` is a client-side stub (empty); WCF throws |
|
||||
| `GetStoreForwardStatusAsync` | ⚠️ | ✅ | gRPC contacts the server (measured idle-state, reports `ErrorOccurred`); WCF returns synthesized all-false. Active-SF magnitude is D2-gated on both |
|
||||
| `ReadEventsAsync` | ✅ | 🔌 | gRPC `RetrievalService.StartEventQuery` / `GetNextEventQueryResultBuffer` / `EndEventQuery` recovered (`bytes btRequest` + handle); not tooled over gRPC |
|
||||
| `GetRuntimeParameterAsync` | ✅ | ✅ | tooled + live-verified over gRPC (`StatusService.GetRuntimeParameter`, the 2020 `GETRP` buffers ride unchanged) |
|
||||
| `GetTagExtendedPropertiesAsync` | ✅ | ✅ | tooled + live-verified over gRPC (`RetrievalService.GetTagExtendedPropertiesFromName`, the `GetTepByNm` buffers ride unchanged) |
|
||||
| `ExecuteSqlCommandAsync` | ✅ | ⛔ | gRPC request rides `RetrievalService.ExecuteSqlCommand`, but the server-side `CSrvDbConnection.ExecuteSqlCommand` faults (`IndexOutOfRange`, native err 38) — an unmet DB-connection precondition; bounded behind `ProtocolEvidenceMissingException`. Use WCF |
|
||||
| `ReadEventsAsync` | ✅ | 🔌 | gRPC `StartEventQuery`/`GetNextEventQueryResultBuffer`/`EndEventQuery` recovered, but the read needs the full CM_EVENT registration state machine (RTag2+EnsT2) ported — not yet tooled |
|
||||
| `SendEventAsync` | ✅ | 🔌 | rides `AddStreamValues` family; no distinct event-send RPC, framing uncaptured over gRPC |
|
||||
| `EnsureTagAsync` / `DeleteTagAsync` / `RenameTagsAsync` | ✅ | 🔌 | gRPC `HistoryService.EnsureTags` / `DeleteTags` / `StartJob`(+`GetJobStatus`) recovered (`bytes btTagInfos`/`btTagnames`/`btInput` + handle) |
|
||||
| `GetTagExtendedPropertiesAsync` / `AddTagExtendedPropertiesAsync` | ✅ | 🔌 | gRPC `RetrievalService.GetTagExtendedPropertiesFromName` + `HistoryService.AddTagExtendedProperties`; gRPC also exposes `DeleteTagExtendedProperties` (WCF delete was server-blocked) |
|
||||
| `ExecuteSqlCommandAsync` | ✅ | 🔌 | gRPC `RetrievalService.ExecuteSqlCommand` (`StrCommand` + `uiOption`, mirrors WCF `ExeC`/`GetR`) |
|
||||
| `GetRuntimeParameterAsync` | ✅ | 🔌 | gRPC `StatusService.GetRuntimeParameter` (`bytes btRequest` + handle) |
|
||||
| `EnsureTagAsync` / `DeleteTagAsync` / `RenameTagsAsync` | ✅ | 🧪 | tooled + routed over gRPC (`HistoryService.EnsureTags` / `DeleteTags` / `StartJob`, write-enabled 0x401 session, WCF serializers reused); sandbox-gated — not yet run destructively against a live box |
|
||||
| `AddTagExtendedPropertiesAsync` | ✅ | 🧪 | tooled + routed over gRPC (`HistoryService.AddTagExtendedProperties`, write-enabled session); sandbox-gated. gRPC also exposes `DeleteTagExtendedProperties` (WCF delete was server-blocked) |
|
||||
| `GetConnectionStatusAsync` | ✅ | ❌ | synthesized from an authenticated probe — no dedicated RPC on either transport (gRPC `PingServer`/`GetHistorianConsoleStatus` could synthesize it) |
|
||||
| `ReadBlocksAsync` | ❌ | ❌ | `StartBlockRetrievalQuery` never captured on either transport — throws `ProtocolEvidenceMissingException` |
|
||||
|
||||
In short: **WCF is the broad, mature surface** (every config write, events, SQL,
|
||||
and all reads), while **gRPC is the narrower *tooled* surface** — but the 2023 R2
|
||||
gRPC *contract* is actually a **superset** of WCF. Every 🔌 row above has a
|
||||
recovered RPC carrying the **same opaque `bytes` buffers the existing WCF
|
||||
serializers already emit**, keyed by the same `strHandle`/`uiHandle` session
|
||||
handle the gRPC read path already obtains. So these are **capture-and-wire** items
|
||||
(route the existing serializer into a gRPC orchestrator + golden-capture the
|
||||
framing), **not** protocol-discovery items. We have only *buffer-verified* two
|
||||
gRPC families live — the read chain and `AddStreamValues` — so per the
|
||||
"capture first, never guess wire bytes" rule the 🔌 rows stay untooled until each
|
||||
is captured. The natural production pattern today remains WCF for config/reads and
|
||||
`RemoteGrpc` reserved for `AddHistoricalValuesAsync`.
|
||||
gRPC *contract* is actually a **superset** of WCF. The recovered config RPCs carry
|
||||
the **same opaque `bytes` buffers the existing WCF serializers already emit**,
|
||||
keyed by the same `strHandle`/`uiHandle` session handle the read path obtains —
|
||||
confirmed by tooling the read-side config ops (`GetRuntimeParameter`,
|
||||
`GetTagExtendedProperties`) live: the WCF buffers ride the gRPC RPC unchanged and
|
||||
the server accepts them. Two caveats surfaced when capturing the rest: `ExecuteSqlCommand`
|
||||
is **server-walled** (the front-door `CSrvDbConnection` faults on a DB-connection
|
||||
precondition the managed session doesn't establish — the same *class* of wall as
|
||||
`OpenStorageConnection`), and `ReadEvents` needs the CM_EVENT registration state
|
||||
machine ported. The remaining 🔌 rows are **capture-and-wire** items (route the
|
||||
existing serializer into a gRPC orchestrator + live-capture), not
|
||||
protocol-discovery — but per "capture first, never guess wire bytes" they stay
|
||||
untooled until each is verified live. The natural production pattern today remains
|
||||
WCF for config/writes and `RemoteGrpc` for reads + `AddHistoricalValuesAsync`.
|
||||
|
||||
> A 2023 R2 server reports History interface version 12 (vs. 11 on 2020). The
|
||||
> connect-time version gate accepts both — they are byte-compatible — so gRPC
|
||||
@@ -216,6 +224,7 @@ $env:HISTORIAN_GRPC_TLS = 'true' # gRPC over TLS
|
||||
$env:HISTORIAN_GRPC_DNSID = 'my-2023r2-host' # cert DNS name when connecting by IP
|
||||
$env:HISTORIAN_GRPC_TIMEOUT = '120' # per-call deadline (s); raise for slow links
|
||||
$env:HISTORIAN_WRITE_SANDBOX_TAG = 'MyFloatTag' # gates the AddHistoricalValues write test
|
||||
$env:HISTORIAN_GRPC_WRITE_SANDBOX_TAG = 'SandboxTag' # gates the DESTRUCTIVE tag create/rename/delete lifecycle test
|
||||
```
|
||||
|
||||
The aggregate tests self-calibrate their query window from a real raw sample, so
|
||||
|
||||
Reference in New Issue
Block a user