From 8a553423ed14e0259fb52b38784b8164410093e3 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 5 May 2026 02:59:29 -0400 Subject: [PATCH] =?UTF-8?q?D2:=20definitive=20conclusion=20=E2=80=94=20rev?= =?UTF-8?q?ision-write=20requires=20non-WCF=20storage-engine=20pipe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IL walk of the native wrapper: HistorianAccess.AddRevisionValuesBegin (private, token 0x06006175) -> CClientCommon.AddNonStreamValuesBegin -> CClient.AddNonStreamValuesBegin (8-instr overload) -> CClient.TransactionBegin -> CHistStorageConnection.StartTransaction (token 0x06001FDD) -> CStorageEngineConsoleClient.StartTransaction CStorageEngineConsoleClient is built on STransactPipeClient2 + SCrtMemFile — a shared-memory + named-pipe transport to aaStorageEngine.exe, completely separate from WCF. The WCF ITransactionServiceContract2.AddNonStreamValuesBegin2 op is a server-side relay that requires a pre-existing storage-engine pipe session for the client. Without that pipe session, the WCF relay returns UnknownClient (51) — and there's no way to establish the pipe session via WCF. D2 is unimplementable as a pure-managed-WCF SDK. The native wrapper itself depends on the C++ shared-memory channel; replicating that from managed code would require implementing the storage-engine pipe protocol, which is a major undertaking and out of scope. The ITransactionServiceContract2 declaration in our contracts file stays as documentation; no public API or orchestrator added. HistorianWcfRevisionOrchestrator remains as an internal probe / regression check — re-run the probe test if anyone believes the architecture has changed. 178/178 tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/plans/revision-write-path.md | 52 +++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/docs/plans/revision-write-path.md b/docs/plans/revision-write-path.md index e7b1ac2..b326689 100644 --- a/docs/plans/revision-write-path.md +++ b/docs/plans/revision-write-path.md @@ -175,16 +175,48 @@ A future session that wants to push further should try (in order): chain — confirmed `RTag2` itself succeeds (returns 25-byte response), but `AddNonStreamValuesBegin2` still fails with `UnknownClient`. So RTag2 doesn't cascade client identity to Trx. -2. Try `IStorageServiceContract` ops (`AddT`, `AddTP`) on `/Storage` - — that endpoint isn't currently bound by our SDK but the contract - is declared in `Wcf/Contracts/IStorageServiceContract.cs`. Maybe - one of its ops registers the client with Trx as a side effect. -3. Decompile / IL-walk `aahClientCommon.CClientCommon` methods that - the native code calls between Open2 and AddNonStreamValuesBegin - to find any "client-with-Trx" registration we're missing. -4. As a last resort, decompile `aahClientAccessPoint.exe` (the server - binary) to find what populates Trx's session table — the answer - is in there, just not in the client surface. +2. ⚠️ **OBVIATED 2026-05-05** by finding (3): `IStorageServiceContract` + ops aren't the missing piece either, because the missing piece isn't + on the WCF surface at all. +3. ✅ **DONE 2026-05-05** — IL walk of `aahClientCommon.CClientCommon.AddNonStreamValuesBegin` + ↓ `aahClientCommon.CClient.AddNonStreamValuesBegin` + ↓ `aahClientCommon.CClient.TransactionBegin` + reveals the chain ultimately invokes + **`aahClientCommon.CHistStorageConnection.StartTransaction`** (token + `0x06001FDD`) which calls **`CStorageEngineConsoleClient.StartTransaction`**. + `CStorageEngineConsoleClient` is built on `STransactPipeClient2` + + `SCrtMemFile` — a **shared-memory + named-pipe** transport to the + storage engine, completely separate from WCF. + +### Definitive architectural conclusion (2026-05-05) + +The revision-write path uses **two transports in tandem**: + +1. WCF (`/Hist`, `/Retr`, `/Stat`, `/Trx`) — what our SDK speaks +2. **Shared-memory + named-pipe to `aaStorageEngine.exe`** — what + `CStorageEngineConsoleClient` speaks; the SDK doesn't (and would be + a major project to implement) + +The WCF `ITransactionServiceContract2.AddNonStreamValuesBegin2` op we +were probing is a server-side relay that requires a pre-existing +storage-engine pipe session for the client. That session is established +via the pipe channel, not WCF. Without the pipe-side session, the WCF +relay returns `UnknownClient (51)` — and there's no way to establish +the pipe-side session via WCF. + +**D2 is unimplementable as a pure-managed-WCF SDK.** The native wrapper +itself depends on the C++ shared-memory channel; to replicate that +behavior from a managed client would require implementing the whole +storage-engine pipe protocol, which is out of scope and probably +not viable without deeper RE of `aaStorageEngine.exe` itself. + +The WCF `ITransactionServiceContract2` declaration in our contracts +file is left in place — it's correct as a contract — but no +orchestrator or public surface should be added on top of it. The +`HistorianWcfRevisionOrchestrator` in `src/AVEVA.Historian.Client/Wcf/` +remains as an internal probe / regression check; if anyone ever +believes the architecture has changed, re-run the probe test to +verify the gate still holds. ### Current state of the SDK-direct probe