diff --git a/src/AVEVA.Historian.Client/Grpc/HistorianGrpcEventOrchestrator.cs b/src/AVEVA.Historian.Client/Grpc/HistorianGrpcEventOrchestrator.cs
index 1720728..74e8568 100644
--- a/src/AVEVA.Historian.Client/Grpc/HistorianGrpcEventOrchestrator.cs
+++ b/src/AVEVA.Historian.Client/Grpc/HistorianGrpcEventOrchestrator.cs
@@ -34,13 +34,16 @@ namespace AVEVA.Historian.Client.Grpc;
/// (the read path proved the front-door session is sufficient over gRPC).
///
///
-/// Live status (2026-06-22): the chain runs end-to-end and StartEventQuery succeeds, but
-/// GetNextEventQueryResultBuffer long-polls when the query has no rows — it blocks to the
-/// call deadline instead of returning the synchronous 5-byte code-85 terminal the 2020 WCF op returns.
-/// A poll-deadline expiry is therefore treated as the no-data terminal (see the loop). The idle dev box
-/// holds no events, so row-level retrieval is not yet live-verified; verifying parsed rows over
-/// gRPC awaits an event-bearing 2023 R2 server. This is tooled + completes cleanly, NOT proven to
-/// return rows.
+/// Live status — server-gated (settled 2026-06-25): the chain runs end-to-end and
+/// StartEventQuery succeeds, but GetNextEventQueryResultBuffer long-polls to the
+/// no-data terminal (instead of the synchronous 5-byte code-85 terminal the 2020 WCF op returns); a
+/// poll-deadline expiry is treated as that terminal (see the loop). This is not an empty-box
+/// artifact: the live 2023 R2 server holds tens of thousands of events yet scopes 0 rows to a
+/// managed connection. Every client-controllable layer was byte-matched to the stock client that returns
+/// rows (see docs/reverse-engineering/grpc-event-query-capture.md) — the gate is a server-internal
+/// per-connection retrieval working-set, not client-fixable. The legacy WCF transport is not a
+/// fallback on 2023 R2 (docs/reverse-engineering/wcf-event-read-spike-results.md). Tooled +
+/// completes cleanly, but proven NOT to return rows over a managed connection.
///
///
internal sealed class HistorianGrpcEventOrchestrator
@@ -101,9 +104,11 @@ internal sealed class HistorianGrpcEventOrchestrator
{
throw new ProtocolEvidenceMissingException(
$"ReadEvents over gRPC did not return rows within {OverallBudget.TotalSeconds:0}s: StartEventQuery " +
- "succeeds but the CM_EVENT registration replay stalls and GetNextEventQueryResultBuffer long-polls " +
- "(no synchronous code-85 terminal over gRPC). Row-level retrieval is not yet verified over gRPC " +
- "(the dev box holds no events) — use the WCF transport for event reads.");
+ "succeeds but GetNextEventQueryResultBuffer long-polls to the no-data terminal. Event-row retrieval " +
+ "over gRPC is auth-solved but server-gated — the 2023 R2 server scopes 0 rows to a managed connection " +
+ "(see docs/reverse-engineering/grpc-event-query-capture.md). The legacy WCF transport is NOT a fallback " +
+ "on 2023 R2 (live-disproven 2026-06-25: net.tcp is reset at the framing layer — see " +
+ "docs/reverse-engineering/wcf-event-read-spike-results.md), so there is no event-read path on a 2023 R2 historian.");
}
foreach (HistorianEvent evt in events)
@@ -169,16 +174,19 @@ internal sealed class HistorianGrpcEventOrchestrator
// reaches the no-data terminal with ZERO rows (the gRPC server long-polls GetNext rather than
// returning the WCF code-85 terminal), we cannot distinguish "genuinely no events in range"
// from "the CM_EVENT registration replay didn't fully land over gRPC" — so we refuse to return
- // a possibly-false empty list and surface the unverified state instead. An event-bearing 2023 R2
- // server will return rows here and exercise the parse path; flip this once that is captured.
+ // a possibly-false empty list and surface the gated state instead. Proven server-gated: the live
+ // 2023 R2 server holds tens of thousands of events yet scopes 0 to a managed gRPC connection
+ // (grpc-event-query-capture.md); WCF is not a 2023 R2 fallback (wcf-event-read-spike-results.md).
if (events.Count == 0)
{
throw new ProtocolEvidenceMissingException(
"ReadEvents over gRPC: the chain completes and StartEventQuery succeeds, but " +
"GetNextEventQueryResultBuffer returns no rows (it long-polls to the no-data terminal " +
- $"after the CM_EVENT registration replay; last={LastErrorBufferDescription}). Row-level " +
- "retrieval is not yet verified over gRPC (the dev box holds no events) — use the WCF " +
- "transport for event reads until a capture against an event-bearing 2023 R2 server confirms it.");
+ $"after the CM_EVENT registration replay; last={LastErrorBufferDescription}). Event-row retrieval " +
+ "over gRPC is auth-solved but server-gated — the 2023 R2 server scopes 0 rows to a managed connection " +
+ "(see docs/reverse-engineering/grpc-event-query-capture.md). The legacy WCF transport is NOT a fallback " +
+ "on 2023 R2 (live-disproven 2026-06-25: net.tcp is reset at the framing layer — see " +
+ "docs/reverse-engineering/wcf-event-read-spike-results.md).");
}
return events;
diff --git a/src/AVEVA.Historian.Client/Wcf/HistorianWcfEventOrchestrator.cs b/src/AVEVA.Historian.Client/Wcf/HistorianWcfEventOrchestrator.cs
index 779a5a2..c8f81a5 100644
--- a/src/AVEVA.Historian.Client/Wcf/HistorianWcfEventOrchestrator.cs
+++ b/src/AVEVA.Historian.Client/Wcf/HistorianWcfEventOrchestrator.cs
@@ -9,9 +9,13 @@ namespace AVEVA.Historian.Client.Wcf;
///
/// Mirrors HistorianWcfReadOrchestrator but targets IRetrievalServiceContract4 for the event flow.
-/// Event row buffer layout is undecoded as of this pass — when StartEventQuery succeeds, this
-/// orchestrator returns an empty enumeration but logs the row-buffer length via the
-/// diagnostic so a follow-up capture can decode the wire shape.
+/// Applies to legacy 2020-era WCF (net.tcp) historians only. The event row-buffer layout is now
+/// decoded (; verified against real captured rows). Note: a
+/// 2023 R2 historian does NOT serve this WCF transport at all — net.tcp is reset at the framing
+/// layer before any auth (live-disproven 2026-06-25; see
+/// docs/reverse-engineering/wcf-event-read-spike-results.md), so this orchestrator is not a
+/// fallback for 2023 R2 deployments. The native return codes 76/85 noted below were 2020-historian
+/// observations.
///
internal sealed class HistorianWcfEventOrchestrator
{