M3 R3.1: OpenStorageConnection is a dead end (error 85); precondition is front-door RegisterTags
Live-probed StorageService.OpenStorageConnection against the 2023 R2 server over a
write-enabled (0x401) session. Every attempt — sweeping ConnectionMode (0x401/0x402/0x1),
StorageSessionId-in (Open2-GUID / empty), and FreeDiskSpace — returns the IDENTICAL native
error type=4 code=85 ("session not registered"), so it's a structural refusal, not a bad
field value.
Decode (two corroborating facts):
- Error 85 is the same code the event read returns before RegisterTags2 (see
HistorianWcfEventOrchestrator) — a generic "session not registered for this op".
- The 2023 R2 decompile shows OpenStorageConnection lives on a SEPARATE GrpcStorageClient
(the storage engine's SF/snapshot channel, own port + service identity); HistorianAccess
drives non-streamed writes through the native C++ HistorianClient, never this op.
So the roadmap's mapped "missing console session" step was wrong. The real non-streamed-write
precondition is the front-door HistoryService.RegisterTags (RTag2-family) for the target tag —
which is exactly why the R3.1 batch failed at AddNonStreamValues (no tag registered ->
StoreNonStreamValues had no route). Matches the original 2020-WCF D2 hypothesis.
Remaining (both need a native gRPC capture; do not guess bytes): the regular-tag RegisterTags
btTagInfos (only CM_EVENT's tag-GUID form is known) and the AddNonStreamValues btInput.
- HistorianGrpcStorageConnectionProbe + grpc-open-storage-connection CLI (opens nothing
persistent; CloseStorageConnection on success)
- corrected revision-write-path.md §R3.1 follow-up + hcal-roadmap R3.1/R3.2 rows
- gated regression test pinning the error-85 refusal
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:
@@ -76,6 +76,7 @@ try
|
||||
"capture-tag-info" => CaptureTagInfo(args),
|
||||
"grpc-revision-probe" => ProbeGrpcRevision(args),
|
||||
"grpc-nonstream-decode" => ProbeGrpcNonStreamedDecode(args),
|
||||
"grpc-open-storage-connection" => ProbeGrpcOpenStorageConnection(args),
|
||||
_ => UnknownCommand(args[0])
|
||||
};
|
||||
}
|
||||
@@ -3213,6 +3214,43 @@ static int WriteMarker(string[] args)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ProbeGrpcOpenStorageConnection(string[] args)
|
||||
{
|
||||
// Usage: grpc-open-storage-connection <host> [port] [--tls] [--dnsid <name>]
|
||||
// M3 follow-up step 1: probe StorageService.OpenStorageConnection — the missing storage-engine
|
||||
// console-session precondition the R3.1 decode pinned. No btInput to guess (all 12 fields are
|
||||
// typed); the probe sweeps the uncertain VALUES and reports the server response per attempt.
|
||||
// Opens NOTHING persistent — on success it CloseStorageConnections immediately.
|
||||
string host = args.Length > 1 ? args[1] : "localhost";
|
||||
int port = args.Length > 2 && int.TryParse(args[2], out int parsedPort)
|
||||
? parsedPort
|
||||
: HistorianClientOptions.DefaultGrpcPort;
|
||||
bool tls = HasOption(args, "--tls");
|
||||
string? dnsId = GetOption(args, "--dnsid");
|
||||
|
||||
string? user = Environment.GetEnvironmentVariable("HISTORIAN_USER");
|
||||
string? password = Environment.GetEnvironmentVariable("HISTORIAN_PASSWORD");
|
||||
bool explicitCreds = !string.IsNullOrEmpty(user);
|
||||
|
||||
var options = new HistorianClientOptions
|
||||
{
|
||||
Host = host,
|
||||
Port = port,
|
||||
Transport = HistorianTransport.RemoteGrpc,
|
||||
GrpcUseTls = tls,
|
||||
AllowUntrustedServerCertificate = tls,
|
||||
ServerDnsIdentity = dnsId,
|
||||
IntegratedSecurity = !explicitCreds,
|
||||
UserName = user ?? string.Empty,
|
||||
Password = password ?? string.Empty,
|
||||
};
|
||||
|
||||
var probe = new HistorianGrpcStorageConnectionProbe(options);
|
||||
HistorianGrpcOpenStorageConnectionResult result = probe.ProbeAsync(CancellationToken.None).GetAwaiter().GetResult();
|
||||
Console.WriteLine(JsonSerializer.Serialize(result, CreateJsonOptions()));
|
||||
return result.OpenStorageSucceeded ? 0 : 2;
|
||||
}
|
||||
|
||||
static int ProbeGrpcRevision(string[] args)
|
||||
{
|
||||
// Usage: grpc-revision-probe <host> [port] [--tls] [--dnsid <name>] [--insecure-cert]
|
||||
|
||||
Reference in New Issue
Block a user