[F53 partial] enable #![warn(missing_docs)] on consumer crates

mxaccess + mxaccess-compat now carry #![warn(missing_docs)] at the
crate root. Every public item has at least a one-line doc comment
(struct fields, enum variants, trait methods all covered).

Touched items:
- mxaccess::lib: DataChange fields, SecurityContext fields,
  TransportKind variants, TransportCapabilities fields,
  RecoveryEvent variants + their inner fields, SessionOptions
  fields, the full Error / ConnectionError / AuthError /
  ProtocolError / ConfigError / SecurityError taxonomy + nested
  fields, Transport trait method docs.
- mxaccess-compat::lib: DataChangeEvent / BufferedDataChangeEvent /
  WriteCompleteEvent / OperationCompleteEvent fields.

Protocol crates (codec, rpc, galaxy, nmx, callback, asb,
asb-nettcp) deliberately left without the lint per F53's strategy
paragraph — their consumers (mxaccess + mxaccess-compat) already
document the surfaces they re-export, and forcing one-liners on
every transport-internal item adds noise without consumer value.

Verification:
- `RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps` clean.
- `cargo test --workspace` (824 tests) green.
- `cargo clippy --workspace --all-targets -- -D warnings` clean.

design/followups.md F53 marked partially resolved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-06 12:20:47 -04:00
parent d149143535
commit c606736ec3
3 changed files with 157 additions and 39 deletions
+4 -34
View File
@@ -25,39 +25,6 @@ Between each publish: wait for the crate to be indexed before the next one's `ca
**Resolves when:** crates.io shows all 9 crates published + the V1 tag is pushed.
### F49 — Live verification sweep for the M6 features
**Status:** **Resolved 2026-05-06.** All five steps pass live against the local AVEVA install (`docs/M6-live-verification.md`):
- Step 1 (F36 buffered subscribe) — `tests/buffered_subscribe_live.rs`
- Step 2 (F45 buffered recovery replay) — `tests/buffered_recovery_replay_live.rs`
- Step 3 (F47 buffered unsubscribe skip) — `tests/buffered_unsubscribe_skip_live.rs`
- Step 4 (F40 metrics smoke) — `tests/metrics_smoke_live.rs`
- Step 5 (F54 OnWriteComplete) — `tests/lmx_write_complete_live.rs`
F55 (DCOM-managed `INmxSvcCallback`) and F56 (missing `EnsurePublisherConnected` + AdviseSupervisory after RegisterReference for buffered) were the two real Rust-port bugs uncovered along the way; both are resolved.
**Severity:** P1 — closes the live-evidence gap for the M6 work that landed unit-only this session.
**Source:** F36, F40, F45, F47, F54 closeouts — each ships with unit tests but most were not exercised against the live AVEVA install in this session.
**Blocked-by:** F12 hardening (`Session::connect_nmx_auto` returns `RPC_S_SERVER_UNAVAILABLE` (1722) under `cargo test`'s tokio multi-thread runtime — see "Live attempt 2026-05-06" below). The COM-activation path itself works in isolation (`cargo run -p mxaccess-rpc --example com-marshal-probe --features windows-com` succeeds), so the failure is downstream — likely a COM apartment threading issue when CoInitializeEx runs on a tokio worker thread.
**Scope.** Run the following against the live AVEVA host with `MX_LIVE=1`:
1. **F36 buffered subscribe**`cargo run -p mxaccess --example subscribe-buffered -- --tag TestChildObject.TestInt`. Confirm `OnBufferedDataChange`-rate updates flow at the configured cadence; capture wire bytes via `analysis/frida/mx-nmx-trace.js` and confirm exactly one `RegisterReference` (`0x10`) frame with `.property(buffer)` suffix, no separate `SetBufferedUpdateInterval` RPC, and no separate `AdviseSupervisory` follow-up.
2. **F45 recovery replay for buffered** — start the `subscribe-buffered` example, force a `Session::recover_connection` mid-flight (e.g. via a `wwtools` helper that bumps the NMX TCP socket), assert the post-recovery NMX traffic carries an `RegisterReference` (NOT `AdviseSupervisory`) with the same correlation id and `.property(buffer)` suffix.
3. **F47 buffered unsubscribe skip** — instrument `Session::unsubscribe` with a `tracing::debug` log line on the buffered branch, run the example to completion + drop, confirm no `UnAdvise` frame in the wire trace.
4. **F40 metrics** — install a `metrics` exporter (`metrics-exporter-prometheus` is the lightest), run `connect-write-read` + `subscribe` examples with `--features metrics`, confirm at least one counter increment and one histogram observation per metric name in the registered set.
5. **F54 OnWriteComplete (LmxClient round-trip)** — scaffold lives at `crates/mxaccess-compat/tests/lmx_write_complete_live.rs`. Run `cargo test -p mxaccess-compat --features live-windows-com --test lmx_write_complete_live -- --ignored --nocapture` to drive `LmxClient::write` → drain `client.on_write_complete()` and assert the `WriteCompleteEvent { server_handle, item_handle, statuses, is_during_recovery }` shape matches `LMX_OnWriteComplete(int hLMXServerHandle, int phItemHandle, ref MXSTATUS_PROXY[] pVars)`.
**Live attempt 2026-05-06.** Steps 1-4 not run yet. Step 5 attempted; the test compiled and ran past Frida-style `--probe-resolve-oxid-managed-ntlm-integrity` resolution + `--probe-remqi-managed` IPID extraction, but `connect_nmx_auto` (preferred path) and `connect_nmx` (fallback with probe-resolved IPID) both fail with `Status { detail: 1722 }` (RPC_S_SERVER_UNAVAILABLE). The .NET `MxNativeClient.Probe --probe-session-write` runs the same scenario successfully end-to-end against the same AVEVA install, so the wire is functional and the failure is Rust-port specific. Root-caused as F55 (hand-rolled callback exporter rejected by NmxSvc's SCM-side OXID resolution); not a tokio-runtime COM-activation issue.
**Step 5 unblocked 2026-05-06 by F55 / Path A.** `cargo test -p mxaccess-compat --features live-windows-com --test lmx_write_complete_live -- --ignored --nocapture` passes against the live AVEVA install: RegisterEngine2 OK, write round-trips, OnWriteComplete fires with the expected `WriteCompleteEvent { server_handle, item_handle, statuses, is_during_recovery }` shape. Steps 1-4 still pending.
**Step 1 attempted 2026-05-06 — blocked by F56.** Added `crates/mxaccess-compat/tests/buffered_subscribe_live.rs` driving `Session::subscribe_buffered` via `Session::connect_nmx_auto`. RegisterReference completes successfully against the live engine, but no `0x33` DataUpdate frames are ever received — only op-status frames per write and the `0x11` registration-result. The Rust port's wire frame for RegisterReference must differ from the .NET reference's in some field. The codec router was also fixed during this attempt (envelope-peeling for `NmxSubscriptionMessage` and the `0x11` `NmxReferenceRegistrationResultMessage` path were both missing); those are real bugs that would have hidden any DataUpdate had one arrived. F56 captures the open work.
**Definition of done:**
1. Per-feature evidence summary in `docs/M6-live-verification.md` (one paragraph per feature with the wire-trace excerpt or metrics-exporter snapshot).
2. If any feature fails live: file a sub-followup with the captured failure and link it from the evidence doc.
3. F12's tokio-runtime COM activation issue resolved (the `connect_nmx_auto` 1722 error above) so the live tests can actually run.
**Resolves when:** all five features have a live evidence row + no sub-followups remain unresolved.
### F50 — Run the F46 Suspend/Activate Frida capture live
**Severity:** P3 — residual from F46 (script ready, capture not yet run).
**Source:** F46 closeout (`design/followups.md`) + `analysis/frida/mx-nmx-trace.js` header procedure.
@@ -98,6 +65,7 @@ F55 (DCOM-managed `INmxSvcCallback`) and F56 (missing `EnsurePublisherConnected`
**Resolves when:** all three optimisations land or are deliberately rejected with a note in the baseline doc.
### F53 — Enable `#![warn(missing_docs)]` workspace-wide
**Status:** Consumer crates resolved 2026-05-06: `#![warn(missing_docs)]` enabled on `mxaccess` and `mxaccess-compat` lib roots, every public item now carries at least a one-line doc comment, `RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps` clean. Protocol crates (`mxaccess-codec`, `mxaccess-rpc`, `mxaccess-galaxy`, `mxaccess-nmx`, `mxaccess-callback`, `mxaccess-asb`, `mxaccess-asb-nettcp`) deliberately deferred per the strategy paragraph below — their consumers (`mxaccess` + `mxaccess-compat`) already document the surfaces they re-export, and forcing one-liners on every transport-internal item adds noise without consumer value.
**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.
@@ -111,7 +79,9 @@ F55 (DCOM-managed `INmxSvcCallback`) and F56 (missing `EnsurePublisherConnected`
**Resolves when:** the lint is on and the workspace doc build is warning-clean with it.
### F56 — `subscribe` / `subscribe_buffered` complete on the wire but never receive `0x33` DataUpdate frames
**Status:** **Resolved 2026-05-06.** Root cause: `Session::subscribe` and `Session::subscribe_buffered_nmx` were missing the `INmxService2::Connect` + `AddSubscriberEngine` round-trip that the .NET reference's `MxNativeSession.EnsurePublisherConnected` (`cs:516-526`) issues before the first advise against a given publishing engine. Without that pair of RPCs, NmxSvc accepts the subscription registration but the publishing engine never knows our engine is subscribed — so no `0x33` DataUpdate frames flow.
**Status:** **Resolved 2026-05-06.** See Resolved section below for the full closeout.
Root cause: `Session::subscribe` and `Session::subscribe_buffered_nmx` were missing the `INmxService2::Connect` + `AddSubscriberEngine` round-trip that the .NET reference's `MxNativeSession.EnsurePublisherConnected` (`cs:516-526`) issues before the first advise against a given publishing engine. Without that pair of RPCs, NmxSvc accepts the subscription registration but the publishing engine never knows our engine is subscribed — so no `0x33` DataUpdate frames flow.
Diagnosed via wwtools/aalogcli: the `[Warning] NmxSvc | NmxCallback->DataReceived ... failed with error 0x{N}` log lines turned out to be NmxSvc's normal log spam where N is the bufferSize, NOT an actual error — the .NET reference's own probe triggers identical entries while still receiving `0x33` DataUpdate frames successfully. The real issue was that those frames never started being sent in the first place.