[F34 evidence] capture AddMonitoredItems request wire + decoder trace
rust / build / test / clippy / fmt (push) Has been cancelled
rust / build / test / clippy / fmt (push) Has been cancelled
Investigation continued via examples/asb-relay.rs middleman:
captured the .NET probe's verbatim AddMonitoredItems request bytes
(695 bytes with the 3-byte NMF SizedEnvelope header). Saved at
rust/crates/mxaccess-asb/tests/fixtures/add-monitored-items-request-wire.bin
as the ground-truth shape MxDataProvider actually accepts.
New tests/add_monitored_items_request_capture.rs runs decode_envelope
over the capture and dumps every NBFX token to stderr for inspection.
Decoded trace surfaces a SECOND, deeper issue:
The F30 dynamic-dict-resolution post-pass at
envelope.rs::resolve_dict_names_in_tokens mis-maps per-session dict
ids. Decoding the captured request renders namespace-URL slots as
field-name strings:
body[1]=DefaultNamespace { value: Chars("nameField") } ← bogus
body[7]=NamespaceDeclaration { prefix: "i",
value: Chars("activeField") } ← bogus
and leaves most element names as `Static(NN)` instead of resolving
to inline names like `activeField` / `bufferedField` / `itemField`.
This blocks F34's substantive fix (rewrite
build_add_monitored_items_request_body to use DataContract
field-suffix names matching the wire). We can't validate the
rewritten builder against the captured fixture until the dict
post-pass produces the right strings.
design/followups.md F34 updated with two-prerequisite resolution
plan:
1. Fix the F30 dynamic-dict resolution so the captured request
decodes to recognisable inline names.
2. Rewrite the AddMonitoredItems / DeleteMonitoredItems builders
against the now-readable structure (DataContract field names
+ namespace prefixes for ASBIDataV2Contract / ASBContract +
nested DataContract serialization of ItemIdentity inside
`<itemField>` and Variants inside userDataField /
valueDeadbandField).
Workspace: mxaccess-asb 96 → 97 (+1 capture-driven analysis test);
default-feature clippy clean. The HMAC canonical-XML signing path
remains correct (F28 fixtures are byte-equal to .NET); only the
binary NBFX wire body needs the rewrite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
//! F34 — wire-byte trace of a captured `AddMonitoredItemsRequest`.
|
||||
//!
|
||||
//! `tests/fixtures/add-monitored-items-request-wire.bin` is the
|
||||
//! verbatim C→S bytes the .NET probe (`MxAsbClient.Probe --subscribe
|
||||
//! --via=net.tcp://127.0.0.1:8088/...`) sent to MxDataProvider on
|
||||
//! 2026-05-06. The exchange led to a working subscription that
|
||||
//! delivered values; this is the request shape MxDataProvider
|
||||
//! actually accepts.
|
||||
//!
|
||||
//! Test goal: dump every NBFX token in the body so we can read off
|
||||
//! the exact element-name shape (DataContract field-suffix names per
|
||||
//! `[DataMember(Name=...)]`, NOT XmlSerializer property names) and
|
||||
//! re-implement `build_add_monitored_items_request_body` against it.
|
||||
//!
|
||||
//! Frame layout: 3-byte NMF SizedEnvelope header (`06 b4 05`,
|
||||
//! varint length = 692) + 692-byte SOAP envelope.
|
||||
|
||||
#![allow(
|
||||
clippy::unwrap_used,
|
||||
clippy::expect_used,
|
||||
clippy::indexing_slicing,
|
||||
clippy::panic
|
||||
)]
|
||||
|
||||
use mxaccess_asb::decode_envelope;
|
||||
use mxaccess_asb_nettcp::nbfx::DynamicDictionary;
|
||||
|
||||
#[test]
|
||||
fn add_monitored_items_request_capture_decoder_trace() {
|
||||
let raw = std::fs::read(
|
||||
std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("tests/fixtures/add-monitored-items-request-wire.bin"),
|
||||
)
|
||||
.expect("read fixture");
|
||||
assert_eq!(raw.len(), 695, "frame length sanity check");
|
||||
|
||||
// Strip 3-byte NMF SizedEnvelope header.
|
||||
let envelope = &raw[3..];
|
||||
assert_eq!(envelope.len(), 692);
|
||||
|
||||
let mut dict = DynamicDictionary::new();
|
||||
let decoded = decode_envelope(envelope, &mut dict).expect("decode_envelope succeeds");
|
||||
eprintln!("=== body tokens ({} total) ===", decoded.body_tokens.len());
|
||||
for (i, tok) in decoded.body_tokens.iter().enumerate() {
|
||||
eprintln!(" body[{i}]={tok:?}");
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user