D2 (new path): SDK-direct WCF revision orchestrator + probe
Implemented HistorianWcfRevisionOrchestrator that talks WCF directly to /Trx, bypassing the native wrapper entirely. Probes AddNonStreamValuesBegin2 against the live local Historian and surfaces what the server returns. Internal-only API; no public surface added — the path isn't viable yet. Findings (live test against localhost): - ✅ The wire path is reachable. After moving from V1 (uint handle, no errorBuffer) to V2 (string handle GUID, out errorBuffer), the server recognizes the call (no ContractFilter mismatch, no exception). - ✅ Server processes the call and returns a structured 5-byte error buffer: 04 33 00 00 00 = type 4 (CustomError) + code 51 (UnknownClient). - ❌ Tried four handle formats (contextKey upper/lower, storageSessionId upper, ClientHandle as decimal string) — all return the same UnknownClient. - ❌ Adding the full priming chain (Stat.GetV ×2, Stat.GETHI ×2, UpdC3, 6× Stat.GetSystemParameter, AllowRenameTags, Trx.GetV, Stat.GetV, Retr.GetV) — same result. ITransactionServiceContract2 has no Validate/Register/Open op of its own. The client-with-Trx registration must happen via some cross- service side effect we haven't isolated. Important takeaway: the wire-format mismatch is solved (contract method names + parameter shapes match what the server expects). The remaining gap is a single missing initialization step. Documented in docs/plans/revision-write-path.md as concrete next-session steps. 178/178 tests pass (one new probe test added). Probe is gated on HISTORIAN_HOST=localhost. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -134,6 +134,51 @@ path is implementable. If it fails with a server-side cache error,
|
||||
try `RTag2` first. If it still fails, the path is genuinely blocked
|
||||
server-side.
|
||||
|
||||
### SDK-direct probe results (2026-05-05)
|
||||
|
||||
`HistorianWcfRevisionOrchestrator` wires up the priming chain + a probe
|
||||
of `ITransactionServiceContract2.AddNonStreamValuesBegin2(string handle, out string transactionId, out byte[] errorBuffer)`.
|
||||
Live test against `localhost`:
|
||||
|
||||
- ✅ `OpenSucceeded: True` — Hist auth chain + Open2 still work end-to-end
|
||||
- ✅ Trx channel opens, `Trx.GetV` returns interface version 2
|
||||
- ✅ Wire path is recognized — server processes the call (no
|
||||
`ActionNotSupportedException` after switching from the abbreviated
|
||||
`AddNonS2B` to the default action name)
|
||||
- ❌ Server returns structured error `04 33 00 00 00` =
|
||||
type 4 (CustomError) + code 51 (`UnknownClient`) for all four handle
|
||||
formats tried (contextKey GUID upper, storageSessionId upper, contextKey
|
||||
lower, ClientHandle as string)
|
||||
- ❌ Adding the full priming chain (Stat.GetV ×2, Stat.GETHI ×2, UpdC3,
|
||||
6× Stat.GetSystemParameter, AllowRenameTags, Trx.GetV, Stat.GetV,
|
||||
Retr.GetV) doesn't change the result — Trx still rejects with
|
||||
`UnknownClient`
|
||||
|
||||
`ITransactionServiceContract2` exposes only `GetV`, `ForwardSnapshot*`,
|
||||
and `AddNonStreamValues*`. There is no `ValidateClient`, `RegisterClient`,
|
||||
or `Open` on Trx. So the client-with-Trx registration must happen via
|
||||
some cross-service side effect we haven't identified.
|
||||
|
||||
**Important takeaway:** the wire path works at the WCF protocol layer.
|
||||
We're past the "is this even reachable" question. The remaining gap is
|
||||
finding what populates Trx's session table — likely:
|
||||
|
||||
1. `RTag2` on /Hist with a tag whose registration cascades to Trx
|
||||
2. Some `IStorageServiceContract` op that we haven't tried
|
||||
3. An aspect of the C++ HistorianClient initialization that doesn't
|
||||
show up in the IL we've inspected (e.g., the
|
||||
`aahClientCommon.CClientCommon` calls during InitializeProxy)
|
||||
|
||||
A future session that wants to push further should:
|
||||
1. Add `RTag2` for the sandbox tag and retry Begin2 — quick experiment
|
||||
2. If that fails, try sending the IStorageServiceContract.AddT or
|
||||
similar to "introduce" the tag to Trx
|
||||
3. If that fails, do an IL walk of `aahClientCommon.CClientCommon`
|
||||
methods called between Open2 and AddNonStreamValuesBegin in a
|
||||
working native scenario (using a system tag the wrapper would
|
||||
accept — or capturing actual on-wire bytes via the IL-rewrite
|
||||
instrumentation if possible)
|
||||
|
||||
## Decision
|
||||
|
||||
Do **not** add public `WriteRevisionsAsync` / `BeginRevisionAsync` to
|
||||
|
||||
Reference in New Issue
Block a user