[R3/R4 Path A] mxaccess: port Lmx.dll FUN_10100ce0 synthesizer kernel
rust / build / test / clippy / fmt (push) Has been cancelled
rust / cargo public-api drift check (F41) (push) Has been cancelled

Path A landed for R3/R4. The byte->MxStatus synthesizer in Lmx.dll is
FUN_10100ce0 (`analysis/ghidra/exports/Lmx.dll.synthesizer-helpers2-decompile.md`),
a 4-byte u32 LE -> 4-tuple MxStatus decoder used by every NMX-frame
parser in Lmx.dll. The kernel is byte-deterministic and context-free,
so it ports as a pure function -- the operation-tracking state
machine the original verdict deferred is NOT required for synthesis.

Bit layout (per FUN_10100ce0 lines 21-24):
  bit 31:        success    (-1 if set, 0 if clear)
  bits 27..24:   category   (4 bits)
  bits 23..20:   detected_by (4 bits)
  bits 15..0:    detail     (i16 -- low 16 bits, signed)
  bits 30..28, 19..16: reserved/padding

Codec changes:
- MxStatus::from_packed_u32() / ::to_packed_u32() -- the kernel +
  inverse for round-trip parity.
- MxStatus::from_nmx_response_code() -- the constructed-from-response-
  code switch in FUN_1010bd10:741-770 (six proven mappings: 0x01, 0x02
  -> CommunicationError + RequestingNmx; 0x03 -> ConfigurationError +
  RequestingNmx; 0x04 -> ConfigurationError + RespondingNmx; 0x05 ->
  CommunicationError + RespondingNmx; 0x1A -> CommunicationError +
  RequestingNmx).
- MxStatusCategory / MxStatusSource: from_i16/to_i16 promoted to const
  fn so MxStatus::from_packed_u32 can be const.
- NmxOperationStatusMessage::try_parse_process_data_received_body() --
  thin wrapper that peels the outer NmxObservedEnvelope before
  delegating to try_parse_inner. Mirrors
  NmxOperationStatusMessage.TryParseProcessDataReceivedBody (.NET cs:20-32).
- NmxOperationStatusMessage::promote_to_typed() -- entry point that
  returns the existing Status field. Documented as a no-op pass-through
  for now (the 5-byte inner-body wire shape is NOT the same field as
  the 4-byte packed-u32 the kernel decodes); kept for API symmetry.
- 22 new round-trip tests covering the kernel, the response-code
  switch, the proven 0x00/0x41/0xEF completion bytes, and round-trip
  for every canonical sentinel.

mxaccess (Session) changes:
- New OperationKind enum (Write/WriteSecured/Read/Subscribe/
  Unsubscribe/Activate/Suspend/Other).
- New OperationContext struct (correlation_id, op_kind, reference,
  retry_count) -- ground for the F54 follow-on per-operation
  correlation work.
- New OperationStatus event type {raw, status, context,
  is_during_recovery}, mirroring MxNativeOperationStatusEvent (cs:73-78)
  with the typed-MxStatus addition.
- Session::operation_status_events() -> broadcast::Receiver<Arc<
  OperationStatus>> + operation_status_stream() Stream variant.
- callback_router() now tries operation-status parsing first, falling
  through to subscription messages -- matches MxNativeSession
  .OnCallbackReceived dispatch order (cs:574,582,590).
- recover_connection() flips a recovery_active counter (Arc<AtomicU32>
  shared with the router) so OperationStatus.is_during_recovery is
  populated correctly. Mirrors MxNativeSession._recoveryActive
  Volatile.Read at cs:573.
- 3 new router tests covering: status-word frame dispatch + typed
  promotion to WriteCompleteOk; completion-only frames stay verbatim;
  is_during_recovery is stamped from the live counter.

Per-operation context tracking (correlating completion frames back to
outstanding writes/subscribes via the correlation_id) is filed as F54
in design/followups.md. The synthesizer kernel itself is byte-
deterministic, so the kernel and the correlation work are decoupled.

Ghidra evidence (the next-ring xref walk beyond FUN_10114a90):
- analysis/ghidra/exports/Lmx.dll.set-attribute-result-xrefs.md --
  xrefs to OnSetAttributeResult / CancelWithStatus / OperationComplete.
- analysis/ghidra/exports/Lmx.dll.vtable-data-xrefs.md -- vtable-slot
  data xrefs for the virtual-dispatch path.
- analysis/ghidra/exports/Lmx.dll.synthesizer-decompile.md --
  ScanOnDemandCallback::OperationComplete/MultipleOperationComplete
  (FUN_1010b990), RemotePlatformResolver::OperationComplete
  (FUN_1010dc80), and the constructed-from-responseCode synthesizer
  in FUN_1010bd10 (lines 698-770). FUN_1010bd10 is the wire-frame
  receiver that drives the synthesis.
- analysis/ghidra/exports/Lmx.dll.synthesizer-helpers-decompile.md --
  FUN_10003fc0 (the <success %d category %d ...> formatter; confirms
  the 4-tuple layout), FUN_1008f150 (dispatch helper).
- analysis/ghidra/exports/Lmx.dll.synthesizer-helpers2-decompile.md --
  FUN_10100ce0 (the kernel itself), FUN_10100bc0 (3xu16 reader),
  FUN_1005e580 (4-byte stream reader), FUN_1010ee00 (sister NMX-frame
  parser using the same kernel).
- analysis/ghidra/exports/Lmx.dll.synthesizer-callers-xrefs.md --
  caller graph; confirms the kernel is called from many wire-frame
  parsers but each parser shares the single 4-byte decoder.

R3/R4 verdict updated in design/70-risks-and-open-questions.md from
"settled at verbatim-preserve" to "settled per Path A". F54 filed in
design/followups.md for the per-operation correlation work.

cargo build / test / clippy -D warnings / RUSTDOCFLAGS=-D warnings doc
all clean. cargo public-api baselines regenerated for mxaccess and
mxaccess-codec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-06 07:08:36 -04:00
parent 460c61df43
commit c73a33edd8
17 changed files with 4962 additions and 135 deletions
+50 -22
View File
@@ -40,46 +40,74 @@ The `OnBufferedDataChange` **public event shape** the wwtools api-notes describe
**Settles when:** ✅ settled per option (a). Reopen only if a future capture surfaces a per-record layout that diverges from the established 15-byte fixed-prefix-plus-value shape — which would require evidence beyond what F44 found.
### R3 — `OperationComplete` trigger unproven **(settled 2026-05-06 — no mapping table exists; verbatim-preserve is the canonical answer)**
### R3 — `OperationComplete` trigger unproven **(settled 2026-05-06 — Path A landed: synthesizer kernel + typed `OperationStatus` events ported)**
**Severity: P1** (was a blocker; now settled per option: verbatim preserve is the canonical native behaviour)
**Severity: P1** (was a blocker; settled per Path A — typed promotion landed via `MxStatus::from_packed_u32`)
**Status (2026-05-06): SETTLED.** Five-stage Ghidra headless decompile traced the byte-to-`MXSTATUS_PROXY` synthesis path end-to-end across `Lmx.dll` and `LmxProxy.dll`. Logs:
- `analysis/ghidra/exports/Lmx.dll.aadct-decompile.md``aaDCT` symbol
- `analysis/ghidra/exports/LmxProxy.dll.completion-status-decompile.md` — Fire_* event handlers
- `analysis/ghidra/exports/LmxProxy.dll.fire-event-xrefs.md` — xrefs to Fire_*
- `analysis/ghidra/exports/LmxProxy.dll.status-synthesis-decompile.md` — Fire_* callers (`FUN_1001657f` / `FUN_10016b50` / `FUN_10016d4b`)
- `analysis/ghidra/exports/LmxProxy.dll.mxstatus-safearray-decompile.md``FUN_10003f60` (the SafeArray creator)
- `analysis/ghidra/exports/Lmx.dll.set-attribute-result-decompile.md``PreboundReference::OnSetAttributeResult` (`FUN_10114a90`)
**Status (2026-05-06): SETTLED PER PATH A.** The five-stage Ghidra walk that previously settled the verdict at "verbatim preserve" was extended with a sixth stage that found the actual byte→`MXSTATUS_PROXY` synthesizer. It is **`Lmx.dll!FUN_10100ce0`** — a single 4-byte u32 LE → `MxStatus` decoder used by every NMX-frame parser in `Lmx.dll`. Bit layout:
```
bit 31: success (-1 if set, 0 if clear)
bits 27..24: category (4 bits, masked by 0xF)
bits 23..20: detected_by (4 bits, masked by 0xF)
bits 15..0: detail (i16 — low 16 bits, signed)
bits 30..28, 19..16: reserved/padding
```
The Rust port now ships this kernel as [`MxStatus::from_packed_u32`] (and the inverse `to_packed_u32` for round-trip parity). `Session::operation_status_events()` emits typed [`OperationStatus`] events for every `0x32`/`0x33`-or-similar callback the wire delivers; the synthesizer is byte-deterministic and context-free, so the operation-tracking state machine the original verdict deferred is **not** required for the kernel itself. Per-operation context tracking (correlating completion frames back to outstanding writes/subscribes) is filed as a follow-up: see F54 below.
A second mapping was also ported: `MxStatus::from_nmx_response_code` covers the constructed-from-response-code path in `Lmx.dll!FUN_1010bd10:741-770` (`ScanOnDemandCallback::GetResponse`), which builds an `MxStatus` from a 1-byte NMX `responseCode` field when no payload status word is present. Six proven mappings: `0x01`/`0x02``(CommunicationError, RequestingNmx)`, `0x03``(ConfigurationError, RequestingNmx)`, `0x04``(ConfigurationError, RespondingNmx)`, `0x05``(CommunicationError, RespondingNmx)`, `0x1A``(CommunicationError, RequestingNmx)`. Unmapped codes return `None` and the consumer falls back to verbatim preservation per CLAUDE.md "Do not fabricate protocol behavior."
**What about the 1-byte completion frames `0x00`/`0x41`/`0xEF`?** Those are NOT decoded by `FUN_10100ce0` — they're a different wire field (the NMX operation-status callback payload, not the `INmxService.GetResponse2 responseCode` parameter). `Lmx.dll`'s decoder for those frames does not invoke any status-synthesis logic; they propagate as raw byte → `MxStatus { success: 0, Unknown, Unknown, detail: byte }`. The Rust port preserves this exactly. R4 is settled by the same fact (see below).
Logs:
- `analysis/ghidra/exports/Lmx.dll.aadct-decompile.md``aaDCT` symbol (stage 1)
- `analysis/ghidra/exports/LmxProxy.dll.completion-status-decompile.md` — Fire_* event handlers (stage 2)
- `analysis/ghidra/exports/LmxProxy.dll.fire-event-xrefs.md` — xrefs to Fire_* (stage 3)
- `analysis/ghidra/exports/LmxProxy.dll.status-synthesis-decompile.md` — Fire_* callers (stage 4)
- `analysis/ghidra/exports/LmxProxy.dll.mxstatus-safearray-decompile.md``FUN_10003f60` (stage 5)
- `analysis/ghidra/exports/Lmx.dll.set-attribute-result-decompile.md``PreboundReference::OnSetAttributeResult` (stage 6, entry to next ring)
- `analysis/ghidra/exports/Lmx.dll.set-attribute-result-xrefs.md` — xrefs to `OnSetAttributeResult`/`CancelWithStatus`/`OperationComplete` (next-ring discovery)
- `analysis/ghidra/exports/Lmx.dll.synthesizer-decompile.md``ScanOnDemandCallback::OperationComplete`/`MultipleOperationComplete` (`FUN_1010b990`), `RemotePlatformResolver::OperationComplete` (`FUN_1010dc80`), and the constructed-from-responseCode synthesizer `FUN_1010bd10` (lines 698-770)
- `analysis/ghidra/exports/Lmx.dll.synthesizer-helpers-decompile.md``FUN_10003fc0` (the `<success %d category %d ...>` formatter), `FUN_1008f150` (the dispatch helper), `PreboundReference` constructors
- `analysis/ghidra/exports/Lmx.dll.synthesizer-helpers2-decompile.md`**the synthesizer kernel `FUN_10100ce0`** (4-byte u32 → `MxStatus` decoder), `FUN_10100bc0` (3×u16 reader), `FUN_1005e580` (4-byte stream reader), `FUN_1010ee00` (sister NMX-frame parser using the same kernel)
- `analysis/ghidra/exports/Lmx.dll.synthesizer-callers-xrefs.md` — caller graph for the synthesizer ring
Findings, layer by layer (the wire bytes flow inward; the synthesis flows outward):
1. **`Lmx.aaDCT`** at `0x10178fc0` is a `SysAllocString(L"Lmx.aaDCT")` into a global BSTR — a tracing category name, not a status-mapping table. No array / lookup logic.
2. **`MXSTATUS_PROXY`** (16 bytes, Pack=4) is a 4-field marshalled struct: `success: i16` at offset 0, `category: i16` at offset 4, `detectedBy: i16` at offset 8, `detail: i16` at offset 12. It is the *output* of synthesis, not a lookup-table entry.
3. **`LmxProxy.dll` Fire_* event handlers** (`FUN_10015f72`, `FUN_1001611f`, `FUN_10016271`, `FUN_100163c0`) take an *already-populated* `MXSTATUS_PROXY[]` and forward it through ATL connection-point dispatch. No synthesis here.
4. **`LmxProxy.dll` Fire_* callers** (`FUN_1001657f` for OnDataChange / OnBufferedDataChange, `FUN_10016b50` for OnWriteComplete, `FUN_10016d4b` for OperationComplete) call **`FUN_10003f60(out_safearray, in_status_ptr, count=1)`** which creates the SafeArray. `FUN_10003f60` is **a verbatim memcpy** of an existing 14-byte buffer into the SAFEARRAY data — no transformation. Source confirms: bytes flow `*local_8 = *param_2; *(local_8+2) = *(param_2+2); *(local_8+4) = *(param_2+4); local_8[6] = param_2[6]`.
5. **`Lmx.dll` `PreboundReference::OnSetAttributeResult`** (`FUN_10114a90`) — the CALLER of step 4's path — receives an already-populated `short *param_7` status buffer. Its log line confirms the layout: `swprintf_s(L"<success %d category %d detectedBy %d detail %d>", (i16)*p, *(p+2), *(p+4), p[6])`. Its dispatch logic checks typed values (`*local_b6c == -1`, `*(int *)(local_b6c + 2) == 3`) — synthesis is upstream of THIS function too.
4. **`LmxProxy.dll` Fire_* callers** (`FUN_1001657f` for OnDataChange / OnBufferedDataChange, `FUN_10016b50` for OnWriteComplete, `FUN_10016d4b` for OperationComplete) call **`FUN_10003f60(out_safearray, in_status_ptr, count=1)`** which creates the SafeArray. `FUN_10003f60` is **a verbatim memcpy** of an existing 14-byte buffer into the SAFEARRAY data — no transformation.
5. **`Lmx.dll` `PreboundReference::OnSetAttributeResult`** (`FUN_10114a90`) — the CALLER of step 4's path — receives an already-populated `short *param_7` status buffer; synthesis is upstream of THIS function too.
6. **The synthesizer kernel itself**: **`Lmx.dll!FUN_10100ce0`** (see `analysis/ghidra/exports/Lmx.dll.synthesizer-helpers2-decompile.md`). A 4-byte u32 LE read from a stream → 4-tuple `MxStatus` decoder. Pure transformation, no operation-context dependency. Used by every NMX-frame parser in `Lmx.dll` (`FUN_1010bd10` `ScanOnDemandCallback::GetResponse`, `FUN_1010ee00` `AccessManager::ProcessNmxRequest`, `FUN_10110986`, etc.) — the upstream decoder reads the wire bytes, the kernel translates them.
7. **The constructed-when-no-bytes path**: when an NMX `responseCode != 0` arrives without a payload status word, `FUN_1010bd10:741-770` constructs an `MxStatus` from the responseCode itself via a fixed switch. Six proven response codes (1, 2, 3, 4, 5, 0x1A); see the table in the `MxStatus::from_nmx_response_code` doc.
**The synthesizer is the NMX-frame decoder in `Lmx.dll`** that calls `OnSetAttributeResult` / `OnGetAttributeResult` / equivalent OperationComplete handler. That decoder takes raw NMX bytes (e.g. 1-byte `0x00`/`0x41`/`0xEF` completion frames or 5-byte `00 00 50 80 00`-style status words) plus operation context (which item, which engine, retry state, last-write-correlation-id) and computes the populated `MXSTATUS_PROXY`. **There is no static lookup table** — the synthesis is per-message contextual.
**Path A landed.** The synthesizer kernel and the constructed-from-response-code switch were both portable as pure functions — no operation-tracking state machine required for the kernel itself, because `FUN_10100ce0` is byte-deterministic. Rust port:
**Why this means R3/R4 stay at "verbatim preserve" canonically.** Two viable paths exist if a future consumer demands typed promotion (neither is a small Rust patch):
- `mxaccess-codec::status::MxStatus::from_packed_u32(packed: u32) -> MxStatus` — the kernel.
- `mxaccess-codec::status::MxStatus::to_packed_u32() -> u32` — inverse, for round-trip parity.
- `mxaccess-codec::status::MxStatus::from_nmx_response_code(byte: u8) -> Option<MxStatus>` — the response-code switch.
- `mxaccess::OperationKind` + `mxaccess::OperationContext` types for future correlation work (per-operation tracking is filed as F54).
- `mxaccess::Session::operation_status_events()` returns `broadcast::Receiver<Arc<OperationStatus>>`; `operation_status_stream()` returns the `Stream<Item = Result<...>>` variant.
- `mxaccess::OperationStatus { raw, status, context, is_during_recovery }` — matches `MxNativeOperationStatusEvent` (`MxNativeSession.cs:73-78`) plus typed `MxStatus` promotion.
- The callback router (`session::callback_router`) now tries operation-status parsing first, mirroring `MxNativeSession.OnCallbackReceived:574`.
- **Path A — port the synthesizer.** Find every NMX-decoder callsite of `OnSetAttributeResult`/`OnGetAttributeResult`/`OperationComplete` in `Lmx.dll` (next xref ring beyond `FUN_10114a90`); decompile each; reverse-engineer the per-decoder synthesis logic; port to Rust. The synthesis depends on operation-tracking state (item handles, retry counters, correlation ids) the Rust codec does not currently track — so the port is more than a codec change; it's a session-state-machine extension. Estimate: ~1-2 weeks of focused work.
- **Path B — empirical capture pairs.** Run the .NET probe in scenarios that produce each completion byte; capture the (input NMX bytes, observed `MXSTATUS_PROXY`) pair via Frida hooks on `LmxProxy.dll!FUN_10003f60`; build an empirical (byte + context → status) mapping. ~30 min × 6-10 scenarios. Output: a mapping table that approximates the synthesizer without re-implementing it. Risk: the mapping is only valid for the captured operation contexts; new contexts may produce statuses outside the table.
**What about the 1-byte completion frames `0x00`/`0x41`/`0xEF`?** They are NOT decoded by `FUN_10100ce0` (they're a different wire field at a different layer — the NMX operation-status callback payload, not the `INmxService.GetResponse2` responseCode parameter). Per CLAUDE.md "Do not fabricate protocol behavior" they continue to propagate as `MxStatus { success: 0, Unknown, Unknown, detail: byte }`. R4 is settled by the same fact.
**Current best answer:** unchanged `Session::operation_status_events()` exposes `Stream<Item = RawOperationStatus>` carrying frame bytes. Promote to a typed `WriteCompleted` only on the proven `00 00 50 80 00` 5-byte pattern. Other bytes stay raw as `MxStatus { Success: 0, Category: Unknown, DetectedBy: Unknown, Detail: byte }`. The Rust codec mirrors `src/MxNativeCodec/NmxOperationStatusMessage.cs:TryParseInner`. The .NET reference does the same, for the same reason: the synthesizer is too context-dependent to mirror without porting the entire operation-tracking state machine, and that exceeds V1 scope.
**Current best answer:** Path A landed. `Session::operation_status_events()` emits typed `OperationStatus` events. The synthesizer kernel (`MxStatus::from_packed_u32`) is exposed for any consumer that holds a 4-byte packed status word (e.g. extracted from a subscription record's `status: i32` field). Per-operation context (correlating completion frames back to outstanding writes/subscribes) is the next step — filed as F54.
**Reopen when:** either (a) a consumer files a concrete use case for typed promotion of a specific byte+context combination — at which point Path B's empirical capture for that one combination is the cheapest answer; or (b) a major-version bump justifies the operation-tracking state-machine port (Path A). Until then, verbatim preservation is correct by construction.
**Reopen when:** F54 lands per-operation correlation, or a future capture surfaces a fresh wire field whose synthesis logic doesn't reduce to `FUN_10100ce0` + `from_nmx_response_code` (no such field has been observed to date).
### R4 — Completion-only byte mapping **(settled 2026-05-06 — collapses into R3's resolution)**
### R4 — Completion-only byte mapping **(settled 2026-05-06 — verbatim-preserve confirmed; synthesizer doesn't apply at this layer)**
**Severity: P1** (was a blocker; now settled per the same R3 finding)
**Severity: P1** (was a blocker; now settled per the same R3 Path A finding — by exclusion)
**Status (2026-05-06): SETTLED.** Same Ghidra walk as R3. The 1-byte completion frames `0x00`, `0x41`, `0xEF` (`work_remain.md:164174`) are the same intermediate NMX signals that R3 covers. There is no static `MXSTATUS_PROXY[]` byte-indexed table to mirror because the native LMX proxy synthesises `MXSTATUS_PROXY` structs per-event from operation context, not from a lookup.
**Status (2026-05-06): SETTLED.** R3's Path A walk traced the byte→`MxStatus` synthesizer to **`Lmx.dll!FUN_10100ce0`**, a 4-byte u32 LE → `MxStatus` decoder. The 1-byte completion frames `0x00`, `0x41`, `0xEF` (`work_remain.md:164174`) are NOT input to that decoder — they're a different wire field, observed at a different layer (the NMX operation-status callback payload, not the `INmxService.GetResponse2` responseCode parameter or any 4-byte packed status field). `Lmx.dll`'s decoder for the 1-byte completion-only inner body does not invoke any synthesis logic; the bytes propagate untransformed.
**Current best answer:** unchanged — preserve as `RawOperationStatus(u8)` mapping to `MxStatus { Success: 0, Category: Unknown, DetectedBy: Unknown, Detail: byte }`. The .NET reference does the same; the Rust port matches.
**Current best answer:** unchanged — preserve as `MxStatus { Success: 0, Category: Unknown, DetectedBy: Unknown, Detail: byte }`. `mxaccess-codec::NmxOperationStatusMessage::promote_to_typed` returns the verbatim placeholder for these frames; `mxaccess::Session::operation_status_events()` surfaces them via the typed `OperationStatus.status` field with the byte preserved in `detail`.
**Reopen when:** same condition as R3 — a context-aware capture that establishes the synthesis logic per-byte under varying operation context.
**Reopen when:** a fresh capture proves a synthesis rule for a specific 1-byte completion code under a specific operation context (e.g. via Frida pairs `LmxProxy.dll!FUN_10003f60` input vs. observed event payload). At that point file a sub-followup with the captured `(byte, context, observed status)` triple and decide whether to add a typed mapping.
### R5 — Activate / Suspend behaviour **(partially observed — F44 documented client-side trigger; wire-side residual gap filed as F46, hook landed pending live re-run)**
+18
View File
@@ -80,6 +80,24 @@ Between each publish: wait for the crate to be indexed before the next one's `ca
**Resolves when:** all three optimisations land or are deliberately rejected with a note in the baseline doc.
### F54 — Per-operation context correlation for `OperationStatus` events
**Severity:** P2 — the synthesizer kernel landed (R3/R4 Path A); per-operation correlation is the next iteration's work.
**Source:** R3/R4 Path A closeout (`design/70-risks-and-open-questions.md`). The Path A walk found `Lmx.dll!FUN_10100ce0` is the byte→`MxStatus` synthesizer and that the kernel itself is byte-deterministic / context-free; per-operation context (item handle, retry counter, originating call kind) is **not** required for synthesis, but is useful for consumers that want to filter "write completions" from "subscription state changes" or correlate completion frames back to specific outstanding writes.
**Scope.**
1. Add an `outstanding_operations: tokio::sync::Mutex<HashMap<[u8; 16], OperationContext>>` registry on `SessionInner`, parallel to the existing `subscriptions` registry.
2. Insert into the registry at the start of every public Session call that issues an outstanding NMX op: `write*`, `read`, `subscribe*`, `unsubscribe`, `activate`, `suspend`. Key by the 16-byte correlation id the call generates. Mirror the .NET reference's private `_pendingWrites`/`_pendingReads` dictionaries.
3. In `callback_router`, when an `OperationStatus` event is parsed, peek the operation-status frame for any correlation id (the 5-byte `00 00 SS SS CC` shape doesn't carry one, but future shapes might) — when present, look up the registry and populate `OperationStatus.context`. When absent, leave `context = None`.
4. Add a Drop-time sweep: when a `Subscription` is dropped, its registry entry stays for late-arriving completion frames, with a TTL (default 30 s) before removal. Mirrors the .NET reference's "completed" dictionary.
5. Round-trip tests: synthesize a `0x32` callback with a known correlation id, hand-insert a registry entry, assert the emitted `OperationStatus.context` matches.
**Definition of done:**
1. `Session::operation_status_events()` emits `OperationStatus.context = Some(_)` for at least the subscription-state-change path (`0x32` SubscriptionStatus frames carry the item correlation id, which the registry will already hold).
2. Round-trip tests demonstrate the populated-context path.
3. R3 in `70-risks-and-open-questions.md` updated from "Path A landed (kernel only)" to "Path A complete (kernel + correlation)".
**Resolves when:** the registry lives and at least one wire path emits a populated `context`.
### F53 — Enable `#![warn(missing_docs)]` workspace-wide
**Severity:** P3 — doc-coverage tightening; not a correctness or release blocker.
**Source:** F42 closeout — the missing-docs lint was deferred because enabling it surfaces hundreds of low-priority public-item gaps that are out of scope for that F-number.
+27 -12
View File
@@ -514,7 +514,9 @@ pub mxaccess_codec::operation_status::NmxOperationStatusMessage::status: mxacces
pub mxaccess_codec::operation_status::NmxOperationStatusMessage::status_code: u16
impl mxaccess_codec::operation_status::NmxOperationStatusMessage
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::is_mx_access_write_complete(&self) -> bool
pub const fn mxaccess_codec::operation_status::NmxOperationStatusMessage::promote_to_typed(&self) -> mxaccess_codec::status::MxStatus
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::try_parse_inner(inner: &[u8]) -> core::result::Result<Self, mxaccess_codec::error::CodecError>
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::try_parse_process_data_received_body(body: &[u8]) -> core::result::Result<Self, mxaccess_codec::error::CodecError>
impl core::clone::Clone for mxaccess_codec::operation_status::NmxOperationStatusMessage
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::clone(&self) -> mxaccess_codec::operation_status::NmxOperationStatusMessage
impl core::cmp::Eq for mxaccess_codec::operation_status::NmxOperationStatusMessage
@@ -618,8 +620,8 @@ pub mxaccess_codec::prelude::MxStatusCategory::SoftwareError = 7
pub mxaccess_codec::prelude::MxStatusCategory::Unknown = -1
pub mxaccess_codec::prelude::MxStatusCategory::Warning = 2
impl mxaccess_codec::status::MxStatusCategory
pub fn mxaccess_codec::status::MxStatusCategory::from_i16(value: i16) -> Self
pub fn mxaccess_codec::status::MxStatusCategory::to_i16(self) -> i16
pub const fn mxaccess_codec::status::MxStatusCategory::from_i16(value: i16) -> Self
pub const fn mxaccess_codec::status::MxStatusCategory::to_i16(self) -> i16
impl core::clone::Clone for mxaccess_codec::status::MxStatusCategory
pub fn mxaccess_codec::status::MxStatusCategory::clone(&self) -> mxaccess_codec::status::MxStatusCategory
impl core::cmp::Eq for mxaccess_codec::status::MxStatusCategory
@@ -649,8 +651,8 @@ pub mxaccess_codec::prelude::MxStatusSource::RespondingLmx = 1
pub mxaccess_codec::prelude::MxStatusSource::RespondingNmx = 3
pub mxaccess_codec::prelude::MxStatusSource::Unknown = -1
impl mxaccess_codec::status::MxStatusSource
pub fn mxaccess_codec::status::MxStatusSource::from_i16(value: i16) -> Self
pub fn mxaccess_codec::status::MxStatusSource::to_i16(self) -> i16
pub const fn mxaccess_codec::status::MxStatusSource::from_i16(value: i16) -> Self
pub const fn mxaccess_codec::status::MxStatusSource::to_i16(self) -> i16
impl core::clone::Clone for mxaccess_codec::status::MxStatusSource
pub fn mxaccess_codec::status::MxStatusSource::clone(&self) -> mxaccess_codec::status::MxStatusSource
impl core::cmp::Eq for mxaccess_codec::status::MxStatusSource
@@ -838,7 +840,10 @@ pub const mxaccess_codec::status::MxStatus::INVALID_REFERENCE_CONFIGURATION: Sel
pub const mxaccess_codec::status::MxStatus::SUSPEND_PENDING: Self
pub const mxaccess_codec::status::MxStatus::WRITE_COMPLETE_OK: Self
pub fn mxaccess_codec::status::MxStatus::detail_text(&self) -> core::option::Option<&'static str>
pub const fn mxaccess_codec::status::MxStatus::from_nmx_response_code(response_code: u8) -> core::option::Option<Self>
pub const fn mxaccess_codec::status::MxStatus::from_packed_u32(packed: u32) -> Self
pub fn mxaccess_codec::status::MxStatus::is_ok(&self) -> bool
pub const fn mxaccess_codec::status::MxStatus::to_packed_u32(self) -> u32
impl core::clone::Clone for mxaccess_codec::status::MxStatus
pub fn mxaccess_codec::status::MxStatus::clone(&self) -> mxaccess_codec::status::MxStatus
impl core::cmp::Eq for mxaccess_codec::status::MxStatus
@@ -903,7 +908,9 @@ pub mxaccess_codec::prelude::NmxOperationStatusMessage::status: mxaccess_codec::
pub mxaccess_codec::prelude::NmxOperationStatusMessage::status_code: u16
impl mxaccess_codec::operation_status::NmxOperationStatusMessage
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::is_mx_access_write_complete(&self) -> bool
pub const fn mxaccess_codec::operation_status::NmxOperationStatusMessage::promote_to_typed(&self) -> mxaccess_codec::status::MxStatus
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::try_parse_inner(inner: &[u8]) -> core::result::Result<Self, mxaccess_codec::error::CodecError>
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::try_parse_process_data_received_body(body: &[u8]) -> core::result::Result<Self, mxaccess_codec::error::CodecError>
impl core::clone::Clone for mxaccess_codec::operation_status::NmxOperationStatusMessage
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::clone(&self) -> mxaccess_codec::operation_status::NmxOperationStatusMessage
impl core::cmp::Eq for mxaccess_codec::operation_status::NmxOperationStatusMessage
@@ -1220,8 +1227,8 @@ pub mxaccess_codec::status::MxStatusCategory::SoftwareError = 7
pub mxaccess_codec::status::MxStatusCategory::Unknown = -1
pub mxaccess_codec::status::MxStatusCategory::Warning = 2
impl mxaccess_codec::status::MxStatusCategory
pub fn mxaccess_codec::status::MxStatusCategory::from_i16(value: i16) -> Self
pub fn mxaccess_codec::status::MxStatusCategory::to_i16(self) -> i16
pub const fn mxaccess_codec::status::MxStatusCategory::from_i16(value: i16) -> Self
pub const fn mxaccess_codec::status::MxStatusCategory::to_i16(self) -> i16
impl core::clone::Clone for mxaccess_codec::status::MxStatusCategory
pub fn mxaccess_codec::status::MxStatusCategory::clone(&self) -> mxaccess_codec::status::MxStatusCategory
impl core::cmp::Eq for mxaccess_codec::status::MxStatusCategory
@@ -1251,8 +1258,8 @@ pub mxaccess_codec::status::MxStatusSource::RespondingLmx = 1
pub mxaccess_codec::status::MxStatusSource::RespondingNmx = 3
pub mxaccess_codec::status::MxStatusSource::Unknown = -1
impl mxaccess_codec::status::MxStatusSource
pub fn mxaccess_codec::status::MxStatusSource::from_i16(value: i16) -> Self
pub fn mxaccess_codec::status::MxStatusSource::to_i16(self) -> i16
pub const fn mxaccess_codec::status::MxStatusSource::from_i16(value: i16) -> Self
pub const fn mxaccess_codec::status::MxStatusSource::to_i16(self) -> i16
impl core::clone::Clone for mxaccess_codec::status::MxStatusSource
pub fn mxaccess_codec::status::MxStatusSource::clone(&self) -> mxaccess_codec::status::MxStatusSource
impl core::cmp::Eq for mxaccess_codec::status::MxStatusSource
@@ -1285,7 +1292,10 @@ pub const mxaccess_codec::status::MxStatus::INVALID_REFERENCE_CONFIGURATION: Sel
pub const mxaccess_codec::status::MxStatus::SUSPEND_PENDING: Self
pub const mxaccess_codec::status::MxStatus::WRITE_COMPLETE_OK: Self
pub fn mxaccess_codec::status::MxStatus::detail_text(&self) -> core::option::Option<&'static str>
pub const fn mxaccess_codec::status::MxStatus::from_nmx_response_code(response_code: u8) -> core::option::Option<Self>
pub const fn mxaccess_codec::status::MxStatus::from_packed_u32(packed: u32) -> Self
pub fn mxaccess_codec::status::MxStatus::is_ok(&self) -> bool
pub const fn mxaccess_codec::status::MxStatus::to_packed_u32(self) -> u32
impl core::clone::Clone for mxaccess_codec::status::MxStatus
pub fn mxaccess_codec::status::MxStatus::clone(&self) -> mxaccess_codec::status::MxStatus
impl core::cmp::Eq for mxaccess_codec::status::MxStatus
@@ -1774,8 +1784,8 @@ pub mxaccess_codec::MxStatusCategory::SoftwareError = 7
pub mxaccess_codec::MxStatusCategory::Unknown = -1
pub mxaccess_codec::MxStatusCategory::Warning = 2
impl mxaccess_codec::status::MxStatusCategory
pub fn mxaccess_codec::status::MxStatusCategory::from_i16(value: i16) -> Self
pub fn mxaccess_codec::status::MxStatusCategory::to_i16(self) -> i16
pub const fn mxaccess_codec::status::MxStatusCategory::from_i16(value: i16) -> Self
pub const fn mxaccess_codec::status::MxStatusCategory::to_i16(self) -> i16
impl core::clone::Clone for mxaccess_codec::status::MxStatusCategory
pub fn mxaccess_codec::status::MxStatusCategory::clone(&self) -> mxaccess_codec::status::MxStatusCategory
impl core::cmp::Eq for mxaccess_codec::status::MxStatusCategory
@@ -1805,8 +1815,8 @@ pub mxaccess_codec::MxStatusSource::RespondingLmx = 1
pub mxaccess_codec::MxStatusSource::RespondingNmx = 3
pub mxaccess_codec::MxStatusSource::Unknown = -1
impl mxaccess_codec::status::MxStatusSource
pub fn mxaccess_codec::status::MxStatusSource::from_i16(value: i16) -> Self
pub fn mxaccess_codec::status::MxStatusSource::to_i16(self) -> i16
pub const fn mxaccess_codec::status::MxStatusSource::from_i16(value: i16) -> Self
pub const fn mxaccess_codec::status::MxStatusSource::to_i16(self) -> i16
impl core::clone::Clone for mxaccess_codec::status::MxStatusSource
pub fn mxaccess_codec::status::MxStatusSource::clone(&self) -> mxaccess_codec::status::MxStatusSource
impl core::cmp::Eq for mxaccess_codec::status::MxStatusSource
@@ -2100,7 +2110,10 @@ pub const mxaccess_codec::status::MxStatus::INVALID_REFERENCE_CONFIGURATION: Sel
pub const mxaccess_codec::status::MxStatus::SUSPEND_PENDING: Self
pub const mxaccess_codec::status::MxStatus::WRITE_COMPLETE_OK: Self
pub fn mxaccess_codec::status::MxStatus::detail_text(&self) -> core::option::Option<&'static str>
pub const fn mxaccess_codec::status::MxStatus::from_nmx_response_code(response_code: u8) -> core::option::Option<Self>
pub const fn mxaccess_codec::status::MxStatus::from_packed_u32(packed: u32) -> Self
pub fn mxaccess_codec::status::MxStatus::is_ok(&self) -> bool
pub const fn mxaccess_codec::status::MxStatus::to_packed_u32(self) -> u32
impl core::clone::Clone for mxaccess_codec::status::MxStatus
pub fn mxaccess_codec::status::MxStatus::clone(&self) -> mxaccess_codec::status::MxStatus
impl core::cmp::Eq for mxaccess_codec::status::MxStatus
@@ -2244,7 +2257,9 @@ pub mxaccess_codec::NmxOperationStatusMessage::status: mxaccess_codec::status::M
pub mxaccess_codec::NmxOperationStatusMessage::status_code: u16
impl mxaccess_codec::operation_status::NmxOperationStatusMessage
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::is_mx_access_write_complete(&self) -> bool
pub const fn mxaccess_codec::operation_status::NmxOperationStatusMessage::promote_to_typed(&self) -> mxaccess_codec::status::MxStatus
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::try_parse_inner(inner: &[u8]) -> core::result::Result<Self, mxaccess_codec::error::CodecError>
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::try_parse_process_data_received_body(body: &[u8]) -> core::result::Result<Self, mxaccess_codec::error::CodecError>
impl core::clone::Clone for mxaccess_codec::operation_status::NmxOperationStatusMessage
pub fn mxaccess_codec::operation_status::NmxOperationStatusMessage::clone(&self) -> mxaccess_codec::operation_status::NmxOperationStatusMessage
impl core::cmp::Eq for mxaccess_codec::operation_status::NmxOperationStatusMessage
+120
View File
@@ -57,6 +57,65 @@ impl core::marker::UnsafeUnpin for mxaccess::asb_session::AsbSubscription
impl core::panic::unwind_safe::RefUnwindSafe for mxaccess::asb_session::AsbSubscription
impl core::panic::unwind_safe::UnwindSafe for mxaccess::asb_session::AsbSubscription
pub mod mxaccess::session
#[non_exhaustive] pub enum mxaccess::session::OperationKind
pub mxaccess::session::OperationKind::Activate
pub mxaccess::session::OperationKind::Other
pub mxaccess::session::OperationKind::Read
pub mxaccess::session::OperationKind::Subscribe
pub mxaccess::session::OperationKind::Suspend
pub mxaccess::session::OperationKind::Unsubscribe
pub mxaccess::session::OperationKind::Write
pub mxaccess::session::OperationKind::WriteSecured
impl core::clone::Clone for mxaccess::session::OperationKind
pub fn mxaccess::session::OperationKind::clone(&self) -> mxaccess::session::OperationKind
impl core::cmp::Eq for mxaccess::session::OperationKind
impl core::cmp::PartialEq for mxaccess::session::OperationKind
pub fn mxaccess::session::OperationKind::eq(&self, other: &mxaccess::session::OperationKind) -> bool
impl core::fmt::Debug for mxaccess::session::OperationKind
pub fn mxaccess::session::OperationKind::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::hash::Hash for mxaccess::session::OperationKind
pub fn mxaccess::session::OperationKind::hash<__H: core::hash::Hasher>(&self, state: &mut __H)
impl core::marker::Copy for mxaccess::session::OperationKind
impl core::marker::StructuralPartialEq for mxaccess::session::OperationKind
impl core::marker::Freeze for mxaccess::session::OperationKind
impl core::marker::Send for mxaccess::session::OperationKind
impl core::marker::Sync for mxaccess::session::OperationKind
impl core::marker::Unpin for mxaccess::session::OperationKind
impl core::marker::UnsafeUnpin for mxaccess::session::OperationKind
impl core::panic::unwind_safe::RefUnwindSafe for mxaccess::session::OperationKind
impl core::panic::unwind_safe::UnwindSafe for mxaccess::session::OperationKind
#[non_exhaustive] pub struct mxaccess::session::OperationContext
pub mxaccess::session::OperationContext::correlation_id: [u8; 16]
pub mxaccess::session::OperationContext::op_kind: mxaccess::session::OperationKind
pub mxaccess::session::OperationContext::reference: core::option::Option<alloc::sync::Arc<str>>
pub mxaccess::session::OperationContext::retry_count: u32
impl core::clone::Clone for mxaccess::session::OperationContext
pub fn mxaccess::session::OperationContext::clone(&self) -> mxaccess::session::OperationContext
impl core::fmt::Debug for mxaccess::session::OperationContext
pub fn mxaccess::session::OperationContext::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Freeze for mxaccess::session::OperationContext
impl core::marker::Send for mxaccess::session::OperationContext
impl core::marker::Sync for mxaccess::session::OperationContext
impl core::marker::Unpin for mxaccess::session::OperationContext
impl core::marker::UnsafeUnpin for mxaccess::session::OperationContext
impl core::panic::unwind_safe::RefUnwindSafe for mxaccess::session::OperationContext
impl core::panic::unwind_safe::UnwindSafe for mxaccess::session::OperationContext
#[non_exhaustive] pub struct mxaccess::session::OperationStatus
pub mxaccess::session::OperationStatus::context: core::option::Option<mxaccess::session::OperationContext>
pub mxaccess::session::OperationStatus::is_during_recovery: bool
pub mxaccess::session::OperationStatus::raw: mxaccess_codec::operation_status::NmxOperationStatusMessage
pub mxaccess::session::OperationStatus::status: mxaccess_codec::status::MxStatus
impl core::clone::Clone for mxaccess::session::OperationStatus
pub fn mxaccess::session::OperationStatus::clone(&self) -> mxaccess::session::OperationStatus
impl core::fmt::Debug for mxaccess::session::OperationStatus
pub fn mxaccess::session::OperationStatus::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Freeze for mxaccess::session::OperationStatus
impl core::marker::Send for mxaccess::session::OperationStatus
impl core::marker::Sync for mxaccess::session::OperationStatus
impl core::marker::Unpin for mxaccess::session::OperationStatus
impl core::marker::UnsafeUnpin for mxaccess::session::OperationStatus
impl core::panic::unwind_safe::RefUnwindSafe for mxaccess::session::OperationStatus
impl core::panic::unwind_safe::UnwindSafe for mxaccess::session::OperationStatus
pub struct mxaccess::session::SessionInner
impl core::fmt::Debug for mxaccess::session::SessionInner
pub fn mxaccess::session::SessionInner::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
@@ -208,6 +267,33 @@ impl core::marker::Unpin for mxaccess::Error
impl core::marker::UnsafeUnpin for mxaccess::Error
impl !core::panic::unwind_safe::RefUnwindSafe for mxaccess::Error
impl !core::panic::unwind_safe::UnwindSafe for mxaccess::Error
#[non_exhaustive] pub enum mxaccess::OperationKind
pub mxaccess::OperationKind::Activate
pub mxaccess::OperationKind::Other
pub mxaccess::OperationKind::Read
pub mxaccess::OperationKind::Subscribe
pub mxaccess::OperationKind::Suspend
pub mxaccess::OperationKind::Unsubscribe
pub mxaccess::OperationKind::Write
pub mxaccess::OperationKind::WriteSecured
impl core::clone::Clone for mxaccess::session::OperationKind
pub fn mxaccess::session::OperationKind::clone(&self) -> mxaccess::session::OperationKind
impl core::cmp::Eq for mxaccess::session::OperationKind
impl core::cmp::PartialEq for mxaccess::session::OperationKind
pub fn mxaccess::session::OperationKind::eq(&self, other: &mxaccess::session::OperationKind) -> bool
impl core::fmt::Debug for mxaccess::session::OperationKind
pub fn mxaccess::session::OperationKind::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::hash::Hash for mxaccess::session::OperationKind
pub fn mxaccess::session::OperationKind::hash<__H: core::hash::Hasher>(&self, state: &mut __H)
impl core::marker::Copy for mxaccess::session::OperationKind
impl core::marker::StructuralPartialEq for mxaccess::session::OperationKind
impl core::marker::Freeze for mxaccess::session::OperationKind
impl core::marker::Send for mxaccess::session::OperationKind
impl core::marker::Sync for mxaccess::session::OperationKind
impl core::marker::Unpin for mxaccess::session::OperationKind
impl core::marker::UnsafeUnpin for mxaccess::session::OperationKind
impl core::panic::unwind_safe::RefUnwindSafe for mxaccess::session::OperationKind
impl core::panic::unwind_safe::UnwindSafe for mxaccess::session::OperationKind
#[non_exhaustive] pub enum mxaccess::ProtocolError
pub mxaccess::ProtocolError::Decode
pub mxaccess::ProtocolError::Decode::buffer_len: usize
@@ -391,6 +477,38 @@ impl core::marker::Unpin for mxaccess::DataChange
impl core::marker::UnsafeUnpin for mxaccess::DataChange
impl core::panic::unwind_safe::RefUnwindSafe for mxaccess::DataChange
impl core::panic::unwind_safe::UnwindSafe for mxaccess::DataChange
#[non_exhaustive] pub struct mxaccess::OperationContext
pub mxaccess::OperationContext::correlation_id: [u8; 16]
pub mxaccess::OperationContext::op_kind: mxaccess::session::OperationKind
pub mxaccess::OperationContext::reference: core::option::Option<alloc::sync::Arc<str>>
pub mxaccess::OperationContext::retry_count: u32
impl core::clone::Clone for mxaccess::session::OperationContext
pub fn mxaccess::session::OperationContext::clone(&self) -> mxaccess::session::OperationContext
impl core::fmt::Debug for mxaccess::session::OperationContext
pub fn mxaccess::session::OperationContext::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Freeze for mxaccess::session::OperationContext
impl core::marker::Send for mxaccess::session::OperationContext
impl core::marker::Sync for mxaccess::session::OperationContext
impl core::marker::Unpin for mxaccess::session::OperationContext
impl core::marker::UnsafeUnpin for mxaccess::session::OperationContext
impl core::panic::unwind_safe::RefUnwindSafe for mxaccess::session::OperationContext
impl core::panic::unwind_safe::UnwindSafe for mxaccess::session::OperationContext
#[non_exhaustive] pub struct mxaccess::OperationStatus
pub mxaccess::OperationStatus::context: core::option::Option<mxaccess::session::OperationContext>
pub mxaccess::OperationStatus::is_during_recovery: bool
pub mxaccess::OperationStatus::raw: mxaccess_codec::operation_status::NmxOperationStatusMessage
pub mxaccess::OperationStatus::status: mxaccess_codec::status::MxStatus
impl core::clone::Clone for mxaccess::session::OperationStatus
pub fn mxaccess::session::OperationStatus::clone(&self) -> mxaccess::session::OperationStatus
impl core::fmt::Debug for mxaccess::session::OperationStatus
pub fn mxaccess::session::OperationStatus::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Freeze for mxaccess::session::OperationStatus
impl core::marker::Send for mxaccess::session::OperationStatus
impl core::marker::Sync for mxaccess::session::OperationStatus
impl core::marker::Unpin for mxaccess::session::OperationStatus
impl core::marker::UnsafeUnpin for mxaccess::session::OperationStatus
impl core::panic::unwind_safe::RefUnwindSafe for mxaccess::session::OperationStatus
impl core::panic::unwind_safe::UnwindSafe for mxaccess::session::OperationStatus
pub struct mxaccess::RecoveryPolicy
pub mxaccess::RecoveryPolicy::delay: core::time::Duration
pub mxaccess::RecoveryPolicy::max_attempts: u32
@@ -437,6 +555,8 @@ pub async fn mxaccess::Session::callback_exporter_addr(&self) -> core::option::O
pub fn mxaccess::Session::callbacks(&self) -> tokio::sync::broadcast::Receiver<alloc::sync::Arc<mxaccess_codec::subscription_message::NmxSubscriptionMessage>>
pub async fn mxaccess::Session::connect_nmx(addr: core::net::socket_addr::SocketAddr, options: mxaccess::SessionOptions, ntlm: mxaccess_rpc::ntlm::NtlmClientContext, service_ipid: mxaccess_rpc::guid::Guid, resolver: alloc::sync::Arc<dyn mxaccess_galaxy::resolver::Resolver>, recovery: mxaccess::RecoveryPolicy) -> core::result::Result<Self, mxaccess::Error>
pub async fn mxaccess::Session::has_recovery_factory(&self) -> bool
pub fn mxaccess::Session::operation_status_events(&self) -> tokio::sync::broadcast::Receiver<alloc::sync::Arc<mxaccess::session::OperationStatus>>
pub fn mxaccess::Session::operation_status_stream(&self) -> impl futures_core::stream::Stream<Item = core::result::Result<alloc::sync::Arc<mxaccess::session::OperationStatus>, mxaccess::Error>> + core::marker::Send
pub async fn mxaccess::Session::read(&self, reference: &str, timeout: core::time::Duration) -> core::result::Result<mxaccess::DataChange, mxaccess::Error>
pub async fn mxaccess::Session::recover_connection(&self, policy: mxaccess::RecoveryPolicy) -> core::result::Result<(), mxaccess::Error>
pub fn mxaccess::Session::recovery_events(&self) -> tokio::sync::broadcast::Receiver<alloc::sync::Arc<mxaccess::RecoveryEvent>>