From 73f66cbf2723c98c4c254a4a0d493896d778a734 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 22 Jun 2026 08:11:27 -0400 Subject: [PATCH] =?UTF-8?q?docs(handoff):=20re-characterize=20gRPC=20event?= =?UTF-8?q?-row=20gate=20=E2=80=94=20capture-gated,=20not=20server-gated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live SQL ground truth (user-authorized one-time read via SOCKS->SQL relay) disproves the gate on the open gRPC event-row item. The live 2023 R2 server IS event-bearing — Runtime.dbo.Events holds 19,356 rows in the last 30 days (90,944 in 365) — yet the empty-filter gRPC event query still returns zero rows and long-polls to the deadline over that same window. So GetNextEventQueryResultBuffer returning nothing is NOT "no events on the server"; the empty-filter request shape (filter / namespace / event-tag registration) doesn't match existing rows. The remaining work is a fresh native gRPC event-query capture of the stock client, not access to a different server. - handoff.md: rewrite open-item #1 with the SQL numbers + capture-gated framing; update the "to move any item" summary to match. - HistorianGrpcIntegrationTests: correct the event-read test comment (drop the false "idle dev box holds no events" rationale; document 19k-events-yet-zero-rows). No behavior change (test edit is comment-only). Sanitization scan clean. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC --- docs/reverse-engineering/handoff.md | 20 ++++++++++++++----- .../HistorianGrpcIntegrationTests.cs | 20 ++++++++++++------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/docs/reverse-engineering/handoff.md b/docs/reverse-engineering/handoff.md index 4b25886..2211a5a 100644 --- a/docs/reverse-engineering/handoff.md +++ b/docs/reverse-engineering/handoff.md @@ -39,8 +39,17 @@ reuses the proven 2020 WCF byte serializers/parsers unchanged inside protobuf **Everything still open is gated — none is a pure-code task:** 1. **gRPC event ROW retrieval** (`ReadEventsAsync` #2) — chain + StartEventQuery - work; `GetNextEventQueryResultBuffer` long-polls on no data. Needs an - **event-bearing 2023 R2 server**. Bounded ≤30s, throws on no-row. + work; `GetNextEventQueryResultBuffer` long-polls and returns zero rows. + **Re-characterized 2026-06-22: this is capture-gated, NOT server-gated.** The + earlier "needs an event-bearing 2023 R2 server" assumption is **disproven** — + the live 2023 R2 server *is* event-bearing (SQL ground truth via the INSQL + linked server: `Runtime.dbo.Events` = 19,356 rows in the last 30 days / + 90,944 in 365 days), yet the **empty-filter** gRPC event query still yields + zero rows over that exact 30-day window and long-polls to the deadline. So + the gap is in the empty-filter request shape (filter / namespace / event-tag + registration), not data availability. Needs a **fresh native gRPC + event-query capture** to see what the stock 2023 R2 client sends. Bounded + ≤30s, throws on no-row. 2. **R4.3 active-SF magnitude** — needs an **SF-active server** (D2 storage-engine console handle). 3. **SendEvent over gRPC** — **capture-gated**: no distinct RPC, framing uncaptured. @@ -58,9 +67,10 @@ reuses the proven 2020 WCF byte serializers/parsers unchanged inside protobuf 8. **Deferred-by-design** items (`write-commands` D1–D3, non-analog tag create, etc.) — bounded out until an explicit customer/user demand signal. -To move any remaining item you need a **different server** (event-bearing or -SF-active), a **fresh native capture** (SendEvent gRPC framing), or a **demand -signal** to unlock a deferred item. Live-server gRPC probe recipe: set +To move any remaining item you need a **fresh native capture** (gRPC event-query +empty-filter framing — item 1; SendEvent gRPC framing — item 3), a **different +server** (SF-active for item 2), or a **demand signal** to unlock a deferred +item. Live-server gRPC probe recipe: set `HISTORIAN_GRPC_HOST`/`_PORT 32565`/`_TLS true`/`_DNSID` + domain creds (strip quotes — `reference_wonder_sql_vd03_credentials`) and run the gated `HistorianGrpcIntegrationTests`. diff --git a/tests/AVEVA.Historian.Client.Tests/HistorianGrpcIntegrationTests.cs b/tests/AVEVA.Historian.Client.Tests/HistorianGrpcIntegrationTests.cs index c724627..9132e04 100644 --- a/tests/AVEVA.Historian.Client.Tests/HistorianGrpcIntegrationTests.cs +++ b/tests/AVEVA.Historian.Client.Tests/HistorianGrpcIntegrationTests.cs @@ -487,13 +487,19 @@ public sealed class HistorianGrpcIntegrationTests // Plan #2: ReadEvents over gRPC. The chain runs end-to-end and StartEventQuery succeeds // (no InvalidOperationException), but — confirmed live 2026-06-22 — GetNextEventQueryResultBuffer - // LONG-POLLS when the query has no rows: the gRPC server blocks to the deadline instead of - // returning the synchronous 5-byte code-85 terminal the 2020 WCF op returns. The idle dev box - // holds no events, so the orchestrator reaches its no-data terminal with zero rows and (rather - // than assert a possibly-false "no events" empty) throws ProtocolEvidenceMissingException. - // This pins that current reality and that the chain stays BOUNDED (no multi-minute hang) via - // the short registration + poll deadlines. Flip to asserting parsed rows once an event-bearing - // 2023 R2 server is available. (Set a small HISTORIAN_GRPC_TIMEOUT to keep this snappy.) + // LONG-POLLS and returns zero rows: the gRPC server blocks to the deadline instead of + // returning the synchronous 5-byte code-85 terminal the 2020 WCF op returns, so the orchestrator + // reaches its no-data terminal with zero rows and (rather than assert a possibly-false "no events" + // empty) throws ProtocolEvidenceMissingException. + // + // IMPORTANT (2026-06-22): the zero rows are NOT "no events on the server". Verified against the + // live 2023 R2 box, which holds 19,356 events in the last 30 days (SQL ground truth via the INSQL + // linked server, Runtime.dbo.Events). The EMPTY-FILTER gRPC event query simply does not match + // them. So the gate here is the empty-filter request shape (filter / namespace / event-tag + // registration), NOT data availability — this is capture-gated (needs a native gRPC event-query + // capture), not server-gated. Flip to asserting parsed rows once that capture lands and the + // request is corrected. The chain stays BOUNDED (no multi-minute hang) via the short + // registration + poll deadlines. (Set a small HISTORIAN_GRPC_TIMEOUT to keep this snappy.) HistorianClient client = new(BuildOptions(host)); DateTime endUtc = DateTime.UtcNow;