M6 live verification: re-run all 5 steps + filter infisical banner
Three doc fixes pinned by re-running today's full live-test sweep:
1. Bump status header from 2026-05-06 to "re-run 2026-05-07" with a
note that all 5 steps still pass against the live AVEVA install.
The first run of step 1 + step 5 today failed with
`Error::Status { detail: 5 }` (DCE/RPC fault 0x00000005) traced
to MX_TEST_DOMAIN being polluted with the infisical CLI's
"A new release of infisical is available" upgrade banner. The
banner was being concatenated onto the domain string by
Setup-LiveProbeEnv.ps1's `2>&1` capture, causing NTLM Type1 to
send a malformed domain field that NmxSvc rejected.
2. Fix tools/Setup-LiveProbeEnv.ps1 — Get-InfisicalSecret now splits
captured output on newlines, filters lines matching the
"^A new release of infisical is available" / "^Please upgrade"
banner patterns, and returns the last non-empty line (the actual
secret value from `infisical secrets get --plain`). Robust to
future banner messages of similar shape.
3. Fix two drifted line citations in docs/M6-live-verification.md:
`recover_connection_core (session.rs:1428-...)` is now at line
1374 after F56/F45/F47 edits — strip the line number, keep the
function name (`Session::recover_connection_core`). Same for
`Session::unsubscribe (session.rs:2261)`.
4. Add "Workspace gate (no live infra needed)" subsection to the
"Reproducing locally" recipe so a fresh contributor sees the
full V1 verification recipe (live + workspace gate) in one place.
All 5 live tests pass post-fix:
- F36 buffered subscribe (drained 1 raw NMX message; no scan
activity on TestChangingInt today, matches 5/6 baseline)
- F45 buffered recovery replay (2 pre + 2 post DataUpdate frames)
- F47 buffered unsubscribe skip (returned Ok)
- F40 metrics smoke (4 expected metric names present)
- F54 OnWriteComplete (status detail 9 = WRITE_COMPLETE_OK)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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.
|
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 |
|
| Step | Feature | Test | Outcome |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
@@ -64,7 +66,7 @@ recover_connection returned Ok — F45 buffered replay path executed
|
|||||||
post-recovery: drained 2 NMX subscription messages
|
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)
|
## Step 3 — F47 buffered unsubscribe skip (PASS)
|
||||||
|
|
||||||
@@ -80,7 +82,7 @@ buffered subscribed, correlation_id = [...]
|
|||||||
buffered unsubscribe returned Ok — F47 skip path verified live
|
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)
|
## Step 4 — F40 metrics live smoke (PASS)
|
||||||
|
|
||||||
@@ -128,6 +130,8 @@ The `WriteCompleteEvent { server_handle, item_handle, statuses, is_during_recove
|
|||||||
|
|
||||||
## Reproducing locally
|
## Reproducing locally
|
||||||
|
|
||||||
|
### Live tests (require AVEVA + MX_LIVE env)
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# 1. Populate live env from Infisical (dot-source so vars persist).
|
# 1. Populate live env from Infisical (dot-source so vars persist).
|
||||||
. .\tools\Setup-LiveProbeEnv.ps1
|
. .\tools\Setup-LiveProbeEnv.ps1
|
||||||
@@ -155,6 +159,18 @@ cargo test -p mxaccess-compat --features live-windows-com `
|
|||||||
--test buffered_unsubscribe_skip_live -- --ignored --nocapture
|
--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
|
## Open work
|
||||||
|
|
||||||
None. F49 sweep complete; F50 (residual Frida capture for Suspend/Activate) closed 2026-05-06 per `docs/F50-suspend-activate-evidence.md`.
|
None. F49 sweep complete; F50 (residual Frida capture for Suspend/Activate) closed 2026-05-06 per `docs/F50-suspend-activate-evidence.md`.
|
||||||
|
|||||||
@@ -72,8 +72,23 @@ function Get-InfisicalSecret {
|
|||||||
if ($LASTEXITCODE -ne 0 -or -not $value) {
|
if ($LASTEXITCODE -ne 0 -or -not $value) {
|
||||||
throw "Get-Secret returned empty for $Env$Path/$Key (exit code $LASTEXITCODE)"
|
throw "Get-Secret returned empty for $Env$Path/$Key (exit code $LASTEXITCODE)"
|
||||||
}
|
}
|
||||||
# Trim any trailing whitespace from the CLI output
|
# The infisical CLI occasionally writes an upgrade-available banner
|
||||||
return ($value | Out-String).Trim()
|
# ("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 {
|
} catch {
|
||||||
throw "Failed to fetch $Env$Path/$Key from Infisical: $_"
|
throw "Failed to fetch $Env$Path/$Key from Infisical: $_"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user