docs(grpc-events): document the server-side/connection angle for next session
Records the row-retrieval pickup now that the v8 ExchangeKey auth is solved and the gap is proven connection-level (not client payload): - grpc-event-query-capture.md: a "NEXT SESSION — the server-side / connection angle" section — what's already proven (don't redo), the in-place tooling, and ordered, testable hypotheses (HTTP/2 vs gRPC-Web transport [leading], TLS client cert, HTTP/2 frame capture, SQL event-store scoping). - handoff.md item 1: updated to "v8 auth solved; row retrieval connection-gated", pointing at the NEXT SESSION section; the "to move any item" summary updated. Doc-only; sanitization scan clean. 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:
@@ -38,26 +38,28 @@ 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) — **CAPTURED + DIAGNOSED
|
||||
2026-06-22 (merged `8ad160b`); remaining gate is now a scoped RE+impl effort,
|
||||
not a capture.** The `capture-event` harness scenario drove the stock 2023 R2
|
||||
client over an Event-type gRPC connection and captured it reading **50 events**
|
||||
(the live server is event-bearing — SQL ground truth via the INSQL linked
|
||||
server: `Runtime.dbo.Events` = 19,356 rows/30d, 90,944/365d). Two gaps vs the
|
||||
SDK: **(a)** the working `StartEventQuery` request is **version 6** (byte 0 =
|
||||
`06` + a 5-byte trailing pad), the SDK sent v5 — **SHIPPED**
|
||||
(`HistorianEventQueryProtocol` `version` param, default 5 = WCF; the gRPC
|
||||
orchestrator passes 6; golden-tested). **(b) the real gate:** rows flow only on
|
||||
an **Event-type connection**. The native `OpenConnection.openParameters` is
|
||||
format **v8** with a `ConnectionType` byte (Event `01` / Process `02`) right
|
||||
after `ClientType`; the SDK's **v6** Open2 buffer has no such field (it writes
|
||||
`ClientType` then `ConnectionMode` back-to-back), so the read-capable v6
|
||||
connection cannot be marked as Event. `ConnectionMode` is not the lever (2020
|
||||
WCF events work at `0x402`). Making event rows flow needs the SDK to emit the
|
||||
native v8 `OpenConnection` with `ConnectionType=Event` (and likely the
|
||||
`ExchangeKey` cert auth path) — a substantial follow-on. Full evidence +
|
||||
byte-level diagnosis: `docs/reverse-engineering/grpc-event-query-capture.md`.
|
||||
Gated test still pins the no-row throw; bounded ≤30s.
|
||||
1. **gRPC event ROW retrieval** (`ReadEventsAsync` #2) — **v8 EVENT-CONNECTION AUTH
|
||||
SOLVED 2026-06-23 (merged `9a25fa4`); row retrieval is now CONNECTION-gated, not
|
||||
a payload gap.** The v8 OpenConnection crypto wall is fully cracked + live-verified:
|
||||
the event connection authenticates via **`HistoryService.ExchangeKey` (P-256 ECDH)
|
||||
→ client key = `SHA256(shared secret)` → credential token = `RC4(password-UTF16LE,
|
||||
key=MD5(client key))`** (the native `HistorianCrypto.NRC4_V2.aahCryptV2` MD5-keyed
|
||||
RC4 scheme). RE'd via Frida CNG hooks + dnlib IL extraction + an offline cracker;
|
||||
implemented pure-managed, golden-tested, auth live-PASSES (past `132/171
|
||||
AuthenticationFailed`). The `StartEventQuery` v6 request and the Event-type v8
|
||||
`OpenConnection` (`ConnectionType=Event`) are also shipped. **BUT** the event query
|
||||
still returns version-11 **rowCount-0** while the native returns 50 for a
|
||||
BYTE-IDENTICAL request. Exhaustively proven NOT a client-payload issue: v8
|
||||
`openParameters`, all str/uint handles, the request, registration (`RTag/EnsT=True`
|
||||
+ order), `queryRequestType=3`, gzip header — **all byte-match the native**. The
|
||||
event RPCs succeed and return a valid EMPTY result (not a transport error), so it's
|
||||
a **connection/server-level scoping difference** (session affinity tied to the
|
||||
native `Grpc.Core` HTTP/2 connection or a connection identity). **Next session: see
|
||||
the "NEXT SESSION — the server-side / connection angle" section of
|
||||
`docs/reverse-engineering/grpc-event-query-capture.md`** (ordered, testable
|
||||
hypotheses: HTTP/2-vs-gRPC-Web transport, TLS client cert, HTTP/2 frame capture, SQL
|
||||
event-store scoping). Orchestrator stays on the no-row throw; `eventConnection: true`
|
||||
is wired; opt-in `EventReadDiagnostic` test (`HISTORIAN_GRPC_EVENT_DIAG=1`).
|
||||
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.
|
||||
@@ -75,10 +77,11 @@ 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 **scoped RE+impl effort** (the v8
|
||||
Event-type `OpenConnection` — item 1, already captured + diagnosed), a **fresh
|
||||
native capture** (SendEvent gRPC framing — item 3), a **different server**
|
||||
(SF-active for item 2), or a **demand signal** to unlock a deferred item.
|
||||
To move any remaining item you need a **server-side / connection-level angle**
|
||||
(item 1 — v8 event auth is solved; row retrieval is connection-gated, see the
|
||||
NEXT SESSION section of `grpc-event-query-capture.md`), a **fresh native capture**
|
||||
(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
|
||||
|
||||
Reference in New Issue
Block a user