[M5] mxaccess-asb: F25 step 9 — Write operation

Closes the highest-value remaining IASBIDataV2 op. With Write landed,
the read+write+subscribe path is functionally complete in-memory.

API additions:
* `MinimalWriteValue { value: AsbVariant }` — carries just the Value
  payload. Optional ArrayElementIndex / Comment / HasQT / Status /
  Timestamp fields are deferred to a later iteration once a live
  capture confirms the WCF DataContract XML form.
* `build_write_request_body(items, values, write_handle)` per
  `AsbContracts.cs:181-194`:
  ```xml
  <WriteBasicRequest xmlns="urn:msg.data.asb.iom:2">
    <Items><ASBIData>{ItemIdentity[] binary}</ASBIData></Items>
    <Values>
      <WriteValue><Value><ASBIData>{Variant binary}</ASBIData></Value></WriteValue>
      ...
    </Values>
    <WriteHandle>{i32}</WriteHandle>
  </WriteBasicRequest>
  ```
  Items array uses the IAsbCustomSerializableType binary fast-path;
  each Value's inner Variant also uses the fast-path. WriteHandle is
  an Int32 (opaque correlation echoed in PublishWriteComplete).
* `decode_write_response` — per-item Status array (mirrors the
  unregister/register pattern).
* `AsbClient::write(items, values, write_handle)` — thin wrapper.

4 new tests:
* `write_request_body_carries_items_values_and_write_handle` — body
  shape sanity (WriteHandle = 7 Int32, WriteValue element present).
* `write_request_body_pairs_items_and_values_arrays` — 2 items + 2
  values produces 2 WriteValue elements.
* `write_response_round_trips_status_array` — Status decode.
* `write_response_missing_status_fails` — graceful MissingField
  error.

Workspace: 695 tests pass (was 691, +4).

Stubbed for next F25 iterations:
* `PublishWriteComplete` — empty request, `ItemWriteComplete[]`
  response.
* `DeleteMonitoredItems` — mirrors AddMonitoredItems pattern.
* Optional WriteValue fields (Comment / Timestamp / etc.) once a
  live capture confirms the wire-byte layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-05 13:04:11 -04:00
parent b543eb1f84
commit 0441a2e693
4 changed files with 231 additions and 14 deletions
+10 -9
View File
@@ -27,14 +27,15 @@ pub use envelope::{
};
pub use operations::{
AddMonitoredItemsResponse, AuthenticationDataBytes, ConnectResponse,
CreateSubscriptionResponse, DeleteSubscriptionResponse, MinimalMonitoredItem, OperationError,
PublishResponse, ReadResponse, RegisterItemsResponse, UnregisterItemsResponse,
build_add_monitored_items_request_body, build_authenticate_me_request_body,
build_connect_request_body, build_create_subscription_request_body,
build_delete_subscription_request_body, build_disconnect_request_body,
build_keep_alive_request_body, build_publish_request_body, build_read_request_body,
build_register_items_request_body, build_unregister_items_request_body,
collect_asbidata_payloads, decode_add_monitored_items_response, decode_connect_response,
CreateSubscriptionResponse, DeleteSubscriptionResponse, MinimalMonitoredItem,
MinimalWriteValue, OperationError, PublishResponse, ReadResponse, RegisterItemsResponse,
UnregisterItemsResponse, WriteResponse, build_add_monitored_items_request_body,
build_authenticate_me_request_body, build_connect_request_body,
build_create_subscription_request_body, build_delete_subscription_request_body,
build_disconnect_request_body, build_keep_alive_request_body, build_publish_request_body,
build_read_request_body, build_register_items_request_body,
build_unregister_items_request_body, build_write_request_body, collect_asbidata_payloads,
decode_add_monitored_items_response, decode_connect_response,
decode_create_subscription_response, decode_publish_response, decode_read_response,
decode_register_items_response, decode_unregister_items_response,
decode_register_items_response, decode_unregister_items_response, decode_write_response,
};