[F33] design/followups: capture live-subscribe wire gap
Live run of `cargo run -p mxaccess --example asb-subscribe` against
the local AVEVA install (with DH params + passphrase loaded from
Setup-LiveProbeEnv.ps1 + Get-AsbPassphrase.ps1) surfaced two concrete
gaps in the subscription-path response decoders:
1. `CreateSubscriptionResponse` returns subscription_id = 0 — the
server almost certainly assigns a real Int64, but
decode_create_subscription_response can't locate the
`<SubscriptionId>` element. Likely a dict-id our F30 post-pass
doesn't resolve for that specific element name.
2. `AddMonitoredItemsResponse` decode fails with MissingField
"Status". The wire shape needs a capture-and-diff vs the .NET
probe's subscription path.
Once subscribe-side ops are issued, the channel desyncs — subsequent
read() on the same session fails with the same MissingField error,
suggesting NBFX framing state may also be out of sync.
The F26 stream API itself (AsbSession::subscribe → Stream<Item =
Result<MonitoredItemValue, Error>>) is complete and unit-tested
(commit f2f22df). This followup just captures the live-wire
reconciliation work that's still required to make the subscribe
path actually return data against MxDataProvider. Once F33 closes,
the last M5 live-wire gap is resolved.
P2 — not blocking M5 closeout; blocks the Subscribe demo.
The asb-subscribe.rs example stays in its working Read-loop form
(no regression). When F33 lands, the example can be promoted to
demonstrate the full subscribe flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -146,6 +146,52 @@ move to `## Resolved` with a date + commit hash.
|
||||
|
||||
F25 (`mxaccess-asb` IASBIDataV2 client) and F26 (`mxaccess::Session` over `AsbTransport`) remain open. With F19-F24 landed, the M5 framing/encoder layer (streams A+B+C+D and the codec stream) is complete; F25 composes them into the `IASBIDataV2` wire client. F22's static dictionary subset is intentionally curated; expand entries as wire captures show new IDs. F27 (constant-time DH) is filed as a separate follow-up below.
|
||||
|
||||
### F33 — Live wire reconciliation for the ASB subscription path
|
||||
**Severity:** P2 — not blocking M5 closeout (the F26 stream API ships with full unit-test coverage), but blocks the `examples/asb-subscribe.rs` Subscribe demo.
|
||||
**Source:** Live run of `cargo run -p mxaccess --example asb-subscribe` against the local AVEVA install, 2026-05-06.
|
||||
|
||||
**Evidence captured live (with `MX_LIVE` + DH params + passphrase from `tools/Setup-LiveProbeEnv.ps1` + `tools/Get-AsbPassphrase.ps1`):**
|
||||
|
||||
```
|
||||
connecting ASB at [fe80::3608:256c:365:cc73%6]:808 ...
|
||||
connected; lifetime=Some("60000:V2")
|
||||
registering TestChildObject.TestInt
|
||||
register status: 0 item(s); first error_code = 0x0000
|
||||
creating subscription (max_queue=100, sample=1s) ...
|
||||
subscription_id = 0 ← suspicious
|
||||
adding monitored items
|
||||
add_monitored_items failed:
|
||||
operation error: response is missing required field Status
|
||||
```
|
||||
|
||||
Two distinct symptoms:
|
||||
|
||||
1. **`CreateSubscriptionResponse` returns `subscription_id = 0`** — the
|
||||
live MxDataProvider almost certainly assigns a real Int64 ID, but
|
||||
`decode_create_subscription_response` (operations.rs:861) walks
|
||||
`body_tokens` looking for `<SubscriptionId>` and finds nothing
|
||||
because the wire emits the element name as a dict-id rather than
|
||||
inline UTF-8. Likely a dict-id we don't yet resolve in the F30
|
||||
post-pass for this specific element.
|
||||
2. **`AddMonitoredItemsResponse` decode fails with `MissingField "Status"`** —
|
||||
`decode_add_monitored_items_response` expects a `<Status>` array
|
||||
payload via `collect_asbidata_payloads`. The server's actual
|
||||
response shape needs a capture-and-diff to compare against the
|
||||
expected layout.
|
||||
|
||||
Once subscribe-side ops are issued, the channel ends up desynced —
|
||||
even subsequent `read()` on the same session fails with the same
|
||||
`MissingField "Status"` error, suggesting NBFX framing state may also
|
||||
be out of sync after the failed subscription decode.
|
||||
|
||||
**Resolves when:** A side-by-side capture via `examples/asb-relay.rs`
|
||||
(TCP middleman) running the .NET probe's subscription path reveals
|
||||
the actual wire bytes for `CreateSubscriptionResponse` +
|
||||
`AddMonitoredItemsResponse`. Reconcile the dict-id resolution and
|
||||
response decoder accordingly. The subscribe path then closes the
|
||||
last live-wire gap on M5 — the F26 stream API itself
|
||||
(`AsbSession::subscribe`) is already complete and unit-tested.
|
||||
|
||||
### F28 — Canonical XML serialiser for `ConnectedRequest` signing (matches `XmlSerializer.Serialize` byte-for-byte)
|
||||
**Status: PARTIALLY RESOLVED.** The five `[XmlSerializerFormat]` ops (AuthenticateMe, Disconnect, KeepAlive, RegisterItems, UnregisterItems) plus the per-action `ValidatorWireFormat` selector + DH-params-from-registry + dynamic-dict id management all landed in commits `f14580e` / `104efc4`. Live AuthenticateMe + RegisterItems work end-to-end (commit `9063f10`). Read / Write / CreateSubscription / AddMonitoredItems / Publish / DeleteMonitored / DeleteSubscription / PublishWriteComplete still sign over NBFX wire bytes via the legacy fallback; works in practice because the live registry has empty `hashAlgorithm` (no HMAC required for the unforced-MAC path), but will break under any deployment that sets a real algorithm. **Severity now P2** — promote back to P0 if a hashAlgorithm-non-empty environment is in scope.
|
||||
**Severity:** P0 — blocks every signed ASB operation (AuthenticateMe, RegisterItems, all data-plane RPCs).
|
||||
|
||||
Reference in New Issue
Block a user