[M5] mxaccess-asb: MX_ASB_TRACE_REPLY trace + F30/F31 followups
Adds env-gated diagnostic trace `MX_ASB_TRACE_REPLY` that, on every incoming SizedEnvelope, prints the raw reply bytes + decoded body tokens (capped at 64) before any consumer-level decode runs. Used to isolate the next blocker after F28's wire-format fixes landed: with canonical XML signing, registry-driven DH params, dynamic-dict id management, ConnectionValidator wire-format-per-action, chunked ASBIData decode, and 0x0A `ShortDictionaryXmlnsAttribute` all in place, AuthenticateMe is accepted by the server and a real RegisterItemsResponse comes back — but it decodes to an opaque token stream of `<b:Static(43)>false</b:Static(43)>` etc. because every field name is dict-encoded against the response's own binary header pre-pop and we never resolve those ids on the read side. Two new follow-ups capture the remaining work: - **F30**: resolve dict-id element/attribute names on the read side. Mirror the F28 write-side fix: read-side dynamic dict accumulates session strings via `intern`, and `decode_tokens` (or a post-pass) needs to substitute `NbfxName::Static(id)` with the resolved `NbfxName::Inline(name)` so downstream `find_element_named` / `collect_asbidata_payloads` match. - **F31**: server response indicates `successField=false` with an empty Status array on Register. Hypotheses (in order): (a) silent HMAC mismatch despite F23 deterministic parity; (b) request-side wire-byte delta the server tolerates but interprets as 0 items; (c) tag does not resolve in the live Galaxy state. Resolution needs F30 first to read the actual Status array + error codes. Workspace: 710 unit tests pass. Clippy clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -170,7 +170,18 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> AsbClient<T> {
|
||||
let record = read_record(&mut self.stream).await?;
|
||||
match record {
|
||||
NmfRecord::SizedEnvelope(reply_bytes) => {
|
||||
let trace_reply = std::env::var("MX_ASB_TRACE_REPLY").ok().is_some();
|
||||
if trace_reply {
|
||||
eprintln!("asb.reply.bytes_len={}", reply_bytes.len());
|
||||
eprintln!("asb.reply.bytes_hex={}", hex_dump(&reply_bytes));
|
||||
}
|
||||
let decoded = decode_envelope(&reply_bytes, &mut self.read_dictionary)?;
|
||||
if trace_reply {
|
||||
eprintln!("asb.reply.body_tokens.len={}", decoded.body_tokens.len());
|
||||
for (i, tok) in decoded.body_tokens.iter().enumerate().take(64) {
|
||||
eprintln!("asb.reply.body[{i}]={tok:?}");
|
||||
}
|
||||
}
|
||||
if let Some(fault) = detect_soap_fault(&decoded) {
|
||||
return Err(fault);
|
||||
}
|
||||
@@ -737,6 +748,14 @@ fn detect_soap_fault(decoded: &crate::DecodedEnvelope) -> Option<ClientError> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Hex dump for diagnostic traces. First 256 bytes only to keep
|
||||
/// MX_ASB_TRACE_REPLY output bounded.
|
||||
fn hex_dump(bytes: &[u8]) -> String {
|
||||
let cap = bytes.len().min(256);
|
||||
let slice = bytes.get(..cap).unwrap_or(&[]);
|
||||
slice.iter().map(|b| format!("{b:02x}")).collect()
|
||||
}
|
||||
|
||||
// ---- error type ----------------------------------------------------------
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
|
||||
Reference in New Issue
Block a user