Lands M3 stream B raw opnum surface: an async NmxClient over the
mxaccess-rpc transport that dispatches all 9 INmxService2 procedures
(GetPartnerVersion, RegisterEngine2 + WithoutCallback, UnregisterEngine,
Connect, AddSubscriberEngine, RemoveSubscriberEngine,
SetHeartbeatSendInterval, TransferData) plus a NonZeroHresult error
variant that mirrors ThrowIfFailed (cs:563-574).
New
- crates/mxaccess-nmx/src/client.rs (~580 LoC, 8 tests including 5
real-socket tokio tests against a hand-rolled DCE/RPC server) — port
of the raw opnum surface from ManagedNmxService2Client.cs.
- NmxClient::connect builds the NTLM-packet-integrity bind path; for
tests, NmxClient::from_bound_transport accepts a transport bound any
way the caller likes (the test server doesn't validate signatures).
- fresh_orpc_this generates a per-call Cid via rand::random(), mirroring
the .NET reference's Guid.NewGuid() at every call site.
- NmxClientError::NonZeroHresult unifies the .NET reference's
Marshal.ThrowExceptionForHR + InvalidOperationException branches so
callers see one typed surface for "transport-OK + LMX rejected".
Cargo.toml: added tokio, tracing, thiserror, rand to mxaccess-nmx.
Two layers of the .NET reference are deliberately out of scope this
iteration; both logged as new followups in design/followups.md:
- F12 (P1): the auto-resolving Create() factory, which needs windows-rs
COM activation (gated by F6) + ComObjRefProvider port.
- F13 (P1): the high-level Write*/Advise*/UnAdvise/RegisterReference
helpers, which depend on GalaxyTagMetadata from M3 stream A (the
Galaxy SQL resolver crate, not yet started).
Test count delta: 389 -> 397 (+8). All four DoD gates green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>