design/70-risks: record the .NET reference's WriteCompleted half-implementation
R3's verdict gains an aside documenting why the original native MxAccess `OnWriteComplete` event has historically only fired for the one exact 5-byte pattern `00 00 50 80 00` (= `MxStatus.WriteCompleteOk`). Verified at: - `src/MxNativeClient/MxNativeCompatibilityServer.cs:756` — `if (!evt.Message.IsMxAccessWriteComplete) return;` gates the consumer-facing `WriteCompleted` event. - `src/MxNativeCodec/NmxOperationStatusMessage.cs:18` — `IsMxAccessWriteComplete` requires `Format == StatusWord && StatusCode == 0x8050 && CompletionCode == 0x00`. Every other completion frame is silently dropped — the 1-byte `0x00`/`0x41`/`0xEF` ones, plus any non-success status word. This was the underlying reason R3/R4 looked unsolvable for a year: the answer "we don't know how to map" was actually "the native compatibility shim deliberately doesn't map these because firing typed failure events on ambiguous bytes was never a goal." Path A's `MxStatus::from_packed_u32` (commit `c73a33e`) closes the asymmetry on the Rust side: `Session::operation_status_events()` exposes ALL typed outcomes the upstream synthesizer produces, not just the WriteCompleteOk slice. The Rust port now has strictly broader operation-status visibility than the .NET reference offered. Recorded so future contributors don't re-derive this from scratch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -60,6 +60,8 @@ A second mapping was also ported: `MxStatus::from_nmx_response_code` covers the
|
||||
|
||||
**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).
|
||||
|
||||
**Aside — the .NET-reference shim was always half-implemented.** Verified at `src/MxNativeClient/MxNativeCompatibilityServer.cs:756` + `src/MxNativeCodec/NmxOperationStatusMessage.cs:18`: `MxNativeCompatibilityServer` fires `WriteCompleted` only when `IsMxAccessWriteComplete` is true, which gates strictly on `Format == StatusWord && StatusCode == 0x8050 && CompletionCode == 0x00` — i.e. the one exact 5-byte pattern `00 00 50 80 00` (= `MxStatus.WriteCompleteOk`). Every other completion frame (the 1-byte `0x00`/`0x41`/`0xEF` ones and any non-success status word) is silently dropped at the gate. The native consumer-facing `WriteCompleted` event has therefore **only ever fired for unambiguous successful writes** — failure outcomes have been invisible at the compatibility-shim layer for the entire history of the .NET reference. Path A's kernel (`from_packed_u32`) closes this asymmetry on the Rust side: `Session::operation_status_events()` exposes **all** typed outcomes the upstream synthesizer produces, not just the WriteCompleteOk slice. The Rust port now has strictly broader operation-status visibility than the .NET reference offered.
|
||||
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user