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