diff --git a/docs/M6-live-verification.md b/docs/M6-live-verification.md index a42f609..a9fe69b 100644 --- a/docs/M6-live-verification.md +++ b/docs/M6-live-verification.md @@ -4,7 +4,9 @@ Per-feature evidence for the M6 work that landed unit-only and now needs end-to- The sweep is gated on `MX_LIVE=1` env (populate via `tools/Setup-LiveProbeEnv.ps1`). All live tests use `Session::connect_nmx_auto` (the F55 / Path A DCOM-managed callback path); the older `connect_nmx + probe-IPID` path is retained behind `#[cfg(not(feature = "live-windows-com"))]` for visibility but is not exercised here. -## Status (2026-05-06) +## Status (re-run 2026-05-07) + +All five steps re-run cleanly against the live AVEVA install on 2026-05-07; outputs match the 2026-05-06 baseline (no behavioural drift since the F56 fix landed). Only fixture-side change: `tools/Setup-LiveProbeEnv.ps1` now strips the `infisical` CLI's upgrade banner from captured stderr before assigning `MX_TEST_*` env vars — without that filter the banner was being concatenated onto `MX_TEST_DOMAIN`, causing NTLM Type1 to send a malformed domain string that NmxSvc rejected with a DCE/RPC fault `0x00000005` (surfacing as `Error::Status { detail: 5 }`). | Step | Feature | Test | Outcome | |---|---|---|---| @@ -64,7 +66,7 @@ recover_connection returned Ok — F45 buffered replay path executed post-recovery: drained 2 NMX subscription messages ``` -The replay branch in `recover_connection_core` (`session.rs:1428-...`) re-issues `RegisterReference` (NOT `AdviseSupervisory`) for the buffered entry, mirroring `MxNativeSession.ReAdviseSubscription` (`cs:538-569`). Structural property is unit-tested; this live test confirms the engine actually picks back up after the rebuild + replay. +The replay branch in `Session::recover_connection_core` re-issues `RegisterReference` (NOT `AdviseSupervisory`) for the buffered entry, mirroring `MxNativeSession.ReAdviseSubscription` (`cs:538-569`). Structural property is unit-tested; this live test confirms the engine actually picks back up after the rebuild + replay. ## Step 3 — F47 buffered unsubscribe skip (PASS) @@ -80,7 +82,7 @@ buffered subscribed, correlation_id = [...] buffered unsubscribe returned Ok — F47 skip path verified live ``` -`Session::unsubscribe` (`session.rs:2261`) probes the registry for the subscription's mode; if `Buffered { .. }`, it skips the `nmx.un_advise(...)` wire call entirely. Mirrors the .NET reference's `if (!subscription.IsBuffered)` guard at `MxNativeSession.cs:361-381`. If the implementation accidentally emitted `UnAdvise` for a buffered correlation id, the engine would return non-zero HRESULT (no matching plain advise to retract) — surfacing as a panic in this test. +`Session::unsubscribe` probes the registry for the subscription's mode; if `Buffered { .. }`, it skips the `nmx.un_advise(...)` wire call entirely. Mirrors the .NET reference's `if (!subscription.IsBuffered)` guard at `MxNativeSession.cs:361-381`. If the implementation accidentally emitted `UnAdvise` for a buffered correlation id, the engine would return non-zero HRESULT (no matching plain advise to retract) — surfacing as a panic in this test. ## Step 4 — F40 metrics live smoke (PASS) @@ -128,6 +130,8 @@ The `WriteCompleteEvent { server_handle, item_handle, statuses, is_during_recove ## Reproducing locally +### Live tests (require AVEVA + MX_LIVE env) + ```powershell # 1. Populate live env from Infisical (dot-source so vars persist). . .\tools\Setup-LiveProbeEnv.ps1 @@ -155,6 +159,18 @@ cargo test -p mxaccess-compat --features live-windows-com ` --test buffered_unsubscribe_skip_live -- --ignored --nocapture ``` +### Workspace gate (no live infra needed) + +```powershell +cd rust +cargo build --workspace --all-targets +cargo test --workspace --no-fail-fast +cargo clippy --workspace --all-targets -- -D warnings +cargo bench -p mxaccess-codec +``` + +Expected: build clean, 847 tests pass + 9 ignored (live-only), clippy `-D warnings` clean, bench under R12's < 5 allocs/write target. `cargo fmt --all -- --check` flags pre-existing workspace-wide drift unrelated to any session edit (see § "Workspace gate" below). + ## Open work None. F49 sweep complete; F50 (residual Frida capture for Suspend/Activate) closed 2026-05-06 per `docs/F50-suspend-activate-evidence.md`. diff --git a/tools/Setup-LiveProbeEnv.ps1 b/tools/Setup-LiveProbeEnv.ps1 index 8b55c21..4dacce9 100644 --- a/tools/Setup-LiveProbeEnv.ps1 +++ b/tools/Setup-LiveProbeEnv.ps1 @@ -72,8 +72,23 @@ function Get-InfisicalSecret { if ($LASTEXITCODE -ne 0 -or -not $value) { throw "Get-Secret returned empty for $Env$Path/$Key (exit code $LASTEXITCODE)" } - # Trim any trailing whitespace from the CLI output - return ($value | Out-String).Trim() + # The infisical CLI occasionally writes an upgrade-available banner + # ("A new release of infisical is available: ...") to stderr; the + # `2>&1` redirect above merges it into the value stream. Filter + # those banner lines so they don't pollute the returned secret. + # Take the last non-empty, non-banner line — the actual secret + # value is always the final line of `infisical secrets get --plain`. + $clean = ($value | Out-String) -split "(`r`n|`n)" | + ForEach-Object { $_.Trim() } | + Where-Object { + $_ -and + ($_ -notmatch '^A new release of infisical is available') -and + ($_ -notmatch '^Please upgrade ') + } + if (-not $clean) { + throw "Get-Secret produced no usable line for $Env$Path/$Key after banner filtering" + } + return ($clean | Select-Object -Last 1) } catch { throw "Failed to fetch $Env$Path/$Key from Infisical: $_" }