Files
mxaccess/docs/Current-Sprint-State.md
T
Joseph Doherty fe2a6db786
rust / build / test / clippy / fmt (push) Has been cancelled
Initial project state: .NET reference, design, Rust port (M0+M1), evidence
Layout:
- src/                    .NET 10 x64 reference: MxNativeCodec, MxNativeClient,
                          MxAsbClient, probes, tests, harnesses. Executable spec.
- design/                 Architectural plan for the Rust port (M0–M6), error
                          model, protocol invariants, risks (R1–R16), adversarial
                          review log (review.md).
- rust/                   Rust workspace. M0 skeleton + M1 codec parity.
                          mxaccess-codec: 215 unit tests + 2 cross-implementation
                          parity tests (byte-identical against .NET reference).
                          Other crates are M0 stubs awaiting M2+.
- captures/               Frida + netsh + pcap evidence per CLAUDE.md
                          ("captures are evidence, not throwaway logs").
- analysis/               Decompiled C# (frida/proxy/decompiled-*),
                          Ghidra exports for native DLLs (`exports/` only —
                          working state at `projects/` and AVEVA's input
                          binaries at `input/` are gitignored).
- docs/                   Reverse-engineering reference docs.
- tools/                  Setup-LiveProbeEnv.ps1 (Infisical credential fetcher),
                          Compute-Crc.ps1 (.NET parity helper).
- .github/workflows/      Rust CI: fmt + build + test + clippy on Windows.
- LICENSE                 MIT (Joseph Doherty, 2026).

Verified:
- cargo test --workspace → 217 passed (215 unit + 2 .NET parity), 0 failed
- cargo clippy --workspace -- -D warnings → clean
- cargo fmt --all -- --check → clean
- cargo publish --dry-run -p mxaccess-codec → packages cleanly

Excluded from history (see .gitignore):
- **/bin, **/obj, **/target — build artifacts
- analysis/ghidra/projects/ — Ghidra working state (regenerable)
- analysis/ghidra/input/ — AVEVA proprietary DLLs (vendor IP)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 06:21:00 -04:00

32 KiB

Current Sprint State

Last updated: 2026-04-26 local VM time.

Build Status

  • MxNativeCodec.Tests: passed.
  • MxNativeClient.Tests: passed, including compatibility surface and recovery lifecycle event checks.
  • MxTraceHarness: Release build passed.
  • MxNativeClient.Probe: Release build passed, including --probe-session-recover-multi.
  • MxDataConsumerProbe: Release build passed. It is an x86 .NET Framework probe for aaMxDataConsumer.dll / IDataConsumer.
  • AsbProxyProbe: Release x64 .NET Framework build passed. It directly loads the MSIL ASB IData proxy/contract assemblies and proves x64 managed discovery, connection, register, read, write, readback, and published write completion against the live MxDataProvider. It also has an unregister compare probe for installed-proxy parity.
  • MxAsbClient.Probe: Release .NET 10 x64 build passed. It is a pure managed ASB client slice with no AVEVA assembly references. It reads the ASB solution shared secret through DPAPI, performs the ASB system-auth handshake, opens the net.tcp IASBIDataV2 channel, and live validates register, read, write, readback, published write completion, unregister parity, and multi-item register/read for TestChildObject.TestInt plus TestMachine_001.TestHistoryValue.
  • MxAsbClient.Probe: clean Release build with zero warnings after adding an explicit System.Security.Cryptography.Xml 10.0.7 package reference and replacing the obsolete PBKDF2 constructor with Rfc2898DeriveBytes.Pbkdf2.
  • MxAsbClient.Tests: passed. The test project covers ASB Variant factory and decode/display round trips for bool, int, float, double, string, datetime, duration, and the matching bool/int/float/double/string/ datetime/duration array wire payloads, MonitoredItemValue binary serializer round trips for publish responses, and ASB status payload decoding for publish quality/status mapping. It also covers the stable ASB connection options overload, endpoint validation, and friend-only debug payload helper visibility, plus write-completion option validation and cancellation-token surface, subscription/monitored-item option overloads, and publish result summary helpers. Latest focused non-live shaping tests also assert exact defaults and validation boundaries for AsbConnectionOptions, AsbWriteOptions, AsbWriteCompletionOptions, AsbSubscriptionOptions, and AsbMonitoredItemOptions, DTO shape for write-completion/readback results, null collection argument guards, empty/non-empty AsbPublishResult helpers, derived status-summary helpers, item-status array mapping, and both compatibility Advise overload signatures.
  • Credential scan over analysis, docs, src, captures, and README.md: no matches for the protected password patterns.

Implemented Surface

  • Public MXAccess method surface is accounted for: Register, Unregister, AddItem, RemoveItem, Advise, UnAdvise, Write, WriteSecured, AuthenticateUser, ArchestrAUserToId, AddItem2, Write2, WriteSecured2, Suspend, Activate, AdviseSupervisory, AddBufferedItem, and SetBufferedUpdateInterval.
  • Public event families are represented: OnDataChange, OnWriteComplete, OperationComplete, and OnBufferedDataChange.
  • WriteSecured2 is implemented and live validated from .NET 10 x64 for the observed authenticated secured-write body shape.
  • WriteSecured remains intentionally unsupported because installed MXAccess returns 0x80004021 for the observed secured/verified paths before emitting a value-bearing NMX body.
  • Object/VARIANT timestamp overloads exist for Write2 and WriteSecured2, matching the installed interop assembly's public API shape.
  • SetHeartbeatSendInterval is exposed and live validated through MxNativeClient.Probe --probe-session-heartbeat --heartbeat-ticks=5 --heartbeat-max-missed=3.
  • Explicit recovery is implemented as MxNativeSession.RecoverConnection() and MxNativeCompatibilityServer.RecoverConnection(serverHandle). The probe --probe-session-recover --tag=TestChildObject.TestInt --value=321 live validated subscribe, recover, preserved subscription count, and write-through against local NmxSvc.
  • RecoverConnectionAsync adds a caller-controlled retry loop via MxNativeRecoveryPolicy. Automatic write retry remains intentionally absent because it can duplicate writes.
  • Recovery lifecycle is observable through RecoveryAttemptStarted, RecoveryAttemptFailed, and RecoveryCompleted on both MxNativeSession and the managed compatibility facade. A live recovery probe with --recover-attempts=2 --recover-delay-ms=100 --value=323 observed one started event, zero failed events, and one completed event.
  • Callback, operation-status, reference-registration, unparsed-callback, compatibility data-change, buffered-data-change, and write-complete payloads now carry IsDuringRecovery. The current policy is pass-through with an explicit marker rather than suppression or buffering.
  • MxNativeClient.Probe --probe-session-recover-multi replays several active subscriptions and counts recovery-window callbacks by callback family.

Runtime Evidence Added In Latest Sprints

  • GR identified TestMachine_001.TestHistoryValue as a deployed, historized integer dynamic attribute.
  • Captures 121 and 122 proved context-bearing buffered registration/result bodies for TestHistoryValue.property(buffer) in context TestMachine_001.
  • Both supervisory and plain advise buffered captures still produced no native Fire_OnBufferedDataChange entry on this VM.
  • Reflection over ArchestrA.MXAccess.dll confirmed the 18-method public method surface, four event families, MxStatus layout, MxStatusCategory, MxStatusSource, and full MxDataType enum values.
  • Installed Lmx.aaDCT detail text has been folded into MxStatusDetails for details 16-61, 541, 542, and 8017.
  • Explicit recovery event reporting is implemented and live validated. The events report attempt number, maximum attempts, exception, and retry intent for failed attempts.
  • A live multi-subscription recovery probe replayed four subscriptions and preserved all four. It observed two data callbacks and four unparsed callbacks overall, but zero callbacks with IsDuringRecovery=true on this VM.
  • A follow-up churn run with --recover-concurrent-writes wrote TestChildObject.TestInt values 330-334 from a separate managed session during recovery. It preserved all four subscriptions and observed four data callbacks overall, including two with IsDuringRecovery=true. This validates the pass-through-with-marker callback policy under live traffic.
  • aaMxDataConsumer.dll was imported with tlbimp into analysis\interop\Interop.aaMxDataConsumer.dll and decompiled under analysis\decompiled-interop\Interop.aaMxDataConsumer. Registry CLSID {85209FB2-0BA1-4594-BBC4-59D3DDAB823D} maps to MxDataConsumer Class.
  • MxDataConsumerProbe can instantiate DataConsumerClass, register IDataConsumerCallback, resolve namespace strings to namespace ID 1, and call ResolveReference, subscribe, ActivateSuspend, and ProcessActivateSuspend2. However, IsConnected(namespaceId) remains 0 for tested namespace strings (Galaxy, ArchestrA, Lmx, localhost, ZB), no registration/subscription responses are produced, and ProcessActivateSuspend2 returns 0x8007139F (ERROR_INVALID_STATE).
  • DataClientClass appears in the imported aaMxDataConsumer type library, but its CLSID {73BC4121-FF89-4762-901C-206E2BD9FE87} is not registered on this node; MxDataConsumerProbe --probe-dataclient reports 0x80040154 (REGDB_E_CLASSNOTREG) before endpoint tests can run.
  • Headless/ILSpy analysis of aaMxDataConsumer.dll shows the COM consumer is a mixed-mode wrapper around managed ASB data proxies. CDataClientCLI creates a DataClientProxy, stores the namespace string, starts an auto-connect worker, and DataClientProxy.Initialize passes that same string as AccessName to IDataProxySelector.SelectProxyForLatestEndpoint.
  • ASBIDataV2Adapter.dll from the GAC contains IDataProxySelector. It first calls ASBDataV2Proxy.FindIDataEndpoint(accessName, DiscoveryScope.Global); if that returns endpoints it constructs ASBDataV2Proxy, otherwise it falls back to V1. The discovery scope is domainname/<accessName>/global.
  • AsbProxyProbe live x64 discovery found one IASBIDataV2 endpoint for access name ZB: net.tcp://desktop-6jl3kko/ASBService/Default_ZB_MxDataProvider/IDataV2. It found no endpoint for Default_ZB_MxDataProvider, Galaxy, localhost, or ZB2.
  • AsbProxyProbe --access=ZB --connect opened the ASB data proxy from an x64 managed process. ASBDataV2Proxy.Connect returned true, channel state was Opened, and PublishWriteComplete returned 0x00000000 with no pending writes. This proves a managed x64 ASB route to LMX/NMX data services exists on this node.
  • AsbProxyProbe --access=ZB --connect --register --read --tag=TestChildObject.TestInt registered and read the test integer through IASBIDataV2. RegisterItems and Read both returned 0x00000000; the item id was 18446462598732840961; the read value was ASB DataType.TypeInt32 (4) with payload 4E010000, decoded as 334.
  • AsbProxyProbe --access=ZB --connect --register --read --write-int=401 --tag=TestChildObject.TestInt accepted a basic ASB write and proved readback. The immediate Write result was globally successful, the per-item synchronous status was 0x0000001F (ArchestrAError.OperationWouldBlock), the next read returned integer value 401, and PublishWriteComplete then returned 0x00000020 (ArchestrAError.PublishComplete) with the original write handle 0xA5B20001 and per-item completion status 0x00000000. This is the first direct evidence that ASB write completion polling can supply the missing operation-completion source without the unstable DataConsumer COM wrapper.
  • Forcing the x86 MxDataConsumerProbe to --namespace=ZB hung in the COM wrapper path and was stopped. The direct ASB route is currently the cleaner path for x64 managed implementation and for any future OperationComplete trigger testing.
  • The pure .NET 10 ASB port in src\MxAsbClient now proves the live data path without loading AVEVA assemblies. Key auth details recovered during the port: this VM's ASB solution registry key is Archestra_DESKTOP-6JL3KKO, HashAlgorthim=None, keySize=256, and the solution overrides the DH prime with the installed 768-bit value. The remaining compatibility fixes were the AVEVA CLR data-contract namespaces/field ordering for ConnectionValidator, WriteValue, ItemStatus, ItemIdentity, and ItemWriteComplete, plus mutable-struct-safe binary decode for nested Variant and ASBStatus values.
  • MxAsbClient.Probe --tag=TestChildObject.TestInt --write-int=412 completed from .NET 10 x64. The run read the previous value 411, accepted write 412 with immediate per-item 0x0000001F (OperationWouldBlock), read back 412, and decoded PublishWriteComplete result 0x00000020, count 1, handle 0xA5B21001, and final per-item status 0x00000000.
  • RegisterItems parity is resolved for the observed startup race. ASB AuthenticateMe is a one-way WCF call; the first immediate RegisterItems can arrive before ASBIDataV2Shim.AuthenticateMe adds the connection implementation. The client now matches installed proxy signing for normal data calls and retries RegisterItems briefly when the immediate result is 0x00000001 (InvalidConnectionId). Stage21 evidence shows first register message 2 returned InvalidConnectionId, retry message 3 returned 0x00000000 with item id 18446462598732840961, and later calls on the same connection succeeded.
  • UnregisterItems is implemented in the pure .NET 10 ASB port and compared against the installed AVEVA ASBDataV2Proxy. Both clients return global success 0x00000000 and the same per-item 0x0000000B (OperationFailed) for the registered TestChildObject.TestInt identity on this provider. Evidence: analysis\proxy\mxasbclient-probe-stage23-unregister-id.txt and analysis\proxy\asbproxyprobe-unregister-compare.txt.
  • Multi-item ASB register/read is implemented and live validated in the pure .NET 10 port. analysis\proxy\mxasbclient-probe-stage24-multi-read.txt registers and reads TestChildObject.TestInt and TestMachine_001.TestHistoryValue in single two-item requests. Both register and read return global 0x00000000 and per-item 0x00000000; the read values decode as ASB TypeInt32 with previews 412 and 303.
  • The pure .NET 10 ASB port now has non-live ASB Variant construction and decode/display coverage for the core scalar and array type matrix: TypeBool, TypeInt32, TypeFloat, TypeDouble, TypeString, TypeDateTime, TypeDuration, and their matching array forms. The public client also exposes a generic Write(tag, Variant, writeHandle) path so the next live write probes can reuse the same encoder instead of being hard-coded to Int32.
  • A live ASB register/read probe validated the deployed scalar and array read type matrix from .NET 10 x64: TestChildObject.TestBool -> TypeBool (17), TestChildObject.TestInt -> TypeInt32 (4), TestChildObject.TestFloat -> TypeFloat (8), TestChildObject.TestDouble -> TypeDouble (9), TestChildObject.TestString -> TypeString (10), TestChildObject.TestDateTime -> TypeDateTime (11), and the matching TestBoolArray[], TestIntArray[], TestFloatArray[], TestDoubleArray[], TestStringArray[], and TestDateTimeArray[] returning ASB array types 57, 44, 48, 49, 50, and 51. All register/read per-item statuses were 0x00000000, and previews decoded correctly.
  • MxAsbClient.Probe now keeps SOAP envelopes and custom serializer byte dumps opt-in through --dump-messages; normal traced runs still show stages, statuses, type IDs, payload lengths, timestamps, and decoded previews without dumping request/response bodies.
  • Pure .NET 10 ASB scalar writes are live validated beyond Int32: TestBool accepted a TypeBool write and later read back False then True; TestFloat wrote/read 13.25; TestDouble wrote/read 13.75; TestString accepted asb-scalar-write and read it back on a delayed follow-up read; TestDateTime wrote/read 2026-04-26T14:33:00Z. These runs confirm the scalar factory payloads are accepted by the live provider. Immediate PublishWriteComplete often returned count 0, and bool/string immediate readback could be stale or time out, so completion polling/readback timing remains part of the production timeout policy gap.
  • Pure .NET 10 ASB array writes are live validated for the deployed dynamic array tags. TestIntArray[] accepted/read back 11-20; TestBoolArray[] accepted/read back alternating false/true values; TestFloatArray[] and TestDoubleArray[] accepted/read back 11.1-20.1; TestStringArray[] accepted/read back K11-T20; and TestDateTimeArray[] accepted/read back ten UTC timestamps from 2026-04-26T14:40:00Z through 2026-04-26T14:49:00Z. Int, bool, and string array readback needed a delayed follow-up read, matching the scalar timing behavior noted above.
  • Production cleanup removed the active ASB build warnings: the vulnerable transitive System.Security.Cryptography.Xml 10.0.0 package is overridden with 10.0.7, dotnet list package --include-transitive --vulnerable now reports no vulnerable packages for MxAsbClient, and the system-auth PBKDF2 derivation uses the non-obsolete static API while preserving the installed proxy's 1000-iteration SHA1 derivation inputs. A live ASB read of TestChildObject.TestInt still succeeds after the authenticator change.
  • Pure .NET 10 ASB subscription/publish is now live-proven for the basic lifecycle. MxAsbClient.Probe --subscribe --publish-count=3 created subscription id 3, added monitored items for TestChildObject.TestInt and TestChildObject.TestString with per-item status 0x00000000, received both values on the second publish poll (TypeInt32 preview 412 and TypeString preview asb-scalar-write), deleted the subscription with global success, and then completed the existing unregister cleanup path. Publish responses returned global 0x00000020, matching the previously observed completion queue success signal, so exact result/status mapping remains open.
  • The ASB publish path now maps raw MonitoredItemValue responses into callback-ready values with item-id-to-tag-name resolution, decoded value, UTC timestamp, MxQuality, and parsed ASB status elements. A live publish run for TestChildObject.TestInt and TestChildObject.TestString decoded quality 0x00C0 and status elements OpcUaStatus:0|OpcUaVendorStatus:0|MxStatusCategory:0|MxStatusDetail:0|MxQuality:192 for both values. The same run added DeleteMonitoredItems, returned global success and per-item 0x00000000 for both monitored identities, then deleted the subscription successfully.
  • MxAsbDataClient now exposes PublishedValueReceived plus PublishValues. PublishValues keeps the raw PublishResponse, maps values through the client's monitored-item id cache, and raises one event per mapped value. A live probe observed published_event[0] for TestChildObject.TestInt and published_event[1] for TestChildObject.TestString, both with quality 0x00C0 and expected previews.
  • MxAsbCompatibilityServer now adapts the pure ASB stream into an MXAccess-like server/item-handle data-change facade. A live MxAsbClient.Probe --compat-subscribe --publish-count=3 run registered ASB server handle 1, added/advised item handles 1 and 2, polled publish, raised two compat_data_change events with values 412 and asb-scalar-write, quality 0x00C0, decoded ASB status elements, removed both monitored items, and unregistered cleanly.
  • The compatibility facade now has an Advise overload that accepts AsbSubscriptionOptions plus AsbMonitoredItemOptions, matching the public ASB subscription shaping instead of forcing positional primitives. The probe compatibility subscribe path now exercises this route, and a live compatibility subscribe run through the options overload registered/advised item handles, published mapped compat_data_change events, removed monitored items, and unregistered cleanly.
  • Initial non-success ASB item-status mapping is implemented. A live probe for DefinitelyMissingObject.DefinitelyMissingAttribute showed global register and read success but per-item read error 0x000A (InvalidMonitoredItems), an empty value with value-status payload decoded as OpcUaStatus:32905|OpcUaVendorStatus:0|MxStatusCategory:750|MxStatusDetail:0|MxQuality:0, and unregister per-item error 0x000B (OperationFailed). Unknown payloads are still preserved rather than guessed.
  • MxAsbClient.Probe --probe-error-cases now keeps broader live ASB non-success evidence opt-in without changing production client behavior. Evidence in analysis\proxy\mxasbclient-probe-error-cases-v2.txt covers: invalid read target global success with per-item 0x000A (InvalidMonitoredItems) plus bad value status; invalid-target async write immediate per-item 0x001F (OperationWouldBlock) followed by PublishWriteComplete global 0x0020 (PublishComplete) and completion per-item 0x0006 (MonitoredItemsNotFound) with status payload OpcUaStatus:6|OpcUaVendorStatus:0|MxStatusCategory:4|MxStatusDetail:6; wrong-type string write to TestChildObject.TestInt immediate per-item 0x001F, completion per-item 0x0013 (WriteFailedBadTypeMismatch) with status payload OpcUaStatus:19|OpcUaVendorStatus:0|MxStatusCategory:4|MxStatusDetail:8001, and unchanged readback value 412; invalid monitored-item cleanup global success with per-item 0x000B (OperationFailed); invalid subscription delete global 0x000C, status 0x0020, specific 0x80020000; and empty subscription publish returning global 0x0020 with no values.
  • ASB result/status summaries now name the full installed ArchestrAError code set, classify publish 0x0020 (PublishComplete) as success-like for publish polling, summarize MxQuality as good/uncertain/bad/unknown, and map known MX status details 16 and 17 to RequestTimedOut and BadNoCommunication while preserving raw category/detail/quality values.
  • Async ASB write completion now has a production-oriented polling helper. WaitForWriteComplete polls PublishWriteComplete for a target write handle until completion or timeout, preserving every raw poll response and completion record. WaitForWriteCompleteAndRead adds optional delayed readback without retrying or duplicating the write. A live probe using --write-int=412 --wait-write-complete --write-complete-timeout-ms=5000 --write-complete-poll-ms=250 --write-readback-delay-ms=500 saw the first completion poll return count 0, the second poll return the matching handle 0xA5B21001, and readback return 412.
  • ASB client disposal now has explicit cleanup reporting. Dispose() delegates to idempotent Cleanup(), sends signed Disconnect best-effort, closes the channel and factory independently, aborts safely after close/fault failures, and records LastCleanupResult with Completed, Succeeded, UsedAbortFallback, and RequiresNewConnection. A live read probe ended with asb.stage=cleanup, asb.stage=disconnect, and asb.cleanup.succeeded=True.
  • ASB reconnect now has an explicit opt-in API. MxAsbDataClient.Reconnect validates caller retry options, optionally cleans up the current connection, returns a new client on success, and preserves attempt plus cleanup evidence without silently replaying reads or writes. A live MxAsbClient.Probe --probe-reconnect --reconnect-attempts=2 --reconnect-delay-ms=250 --cleanup-disconnect-timeout-ms=5000 --cleanup-close-timeout-ms=5000 run read TestChildObject.TestInt as 412, cleaned up and disconnected the original connection with caller cleanup timeouts, connected successfully on attempt 1, re-registered the tag on the new client, read back 412, and completed final cleanup successfully.
  • ASB cleanup partial-failure behavior is now covered in focused local tests without forcing live provider faults. The close-or-abort policy is factored into AsbCommunicationCleanup, and tests cover already-closed objects, faulted objects that skip close and abort directly, close failure followed by abort fallback, abort failure reporting, and propagation of the configured close timeout.
  • ASB cleanup cancellation now has explicit policy. AsbClientCleanupOptions accepts a CancellationToken; when cancellation is already requested, cleanup skips graceful disconnect/close attempts and uses local abort cleanup for non-closed channel/factory objects. Existing disconnect and close timeouts still bound synchronous WCF calls that have already started. A live MxAsbClient.Probe --probe-canceled-cleanup run connected, registered, and read TestChildObject.TestInt as 412, then skipped disconnect and aborted both opened communication objects locally. The cleanup result completed with succeeded=False, abort=True, requires_new=True, and an OperationCanceledException disconnect marker.
  • Safe connection-failure evidence is now captured without destabilizing the live ASB provider. MxAsbClient.Probe --probe-connect-failure --endpoint=net.tcp://localhost:1/ASBService/Default_ZB_MxDataProvider/IDataV2 reports connect_failure_observed=True, an EndpointNotFoundException, and inner SocketException 10061 for a refused local TCP endpoint. Connect now also closes or aborts any WCF channel/factory objects created before a connection setup failure; the refused-endpoint probe reports asb.stage=connect-cleanup before surfacing the exception.
  • OperationComplete candidate evidence was narrowed on the direct ASB route. The IASBIDataV2 contract exposed by the live endpoint has no activate, suspend, or generic operation-complete operation; only PublishWriteComplete exists, and it is write-specific. A live MxAsbClient.Probe --probe-operation-complete-candidates run against TestChildObject.TestInt and TestChildObject.TestString polled PublishWriteComplete before and after create-subscription, add-monitored, publish, delete-monitored, and delete-subscription operations. Every poll returned count 0, while the non-write operations themselves succeeded.
  • ASB buffered-subscription probing is now explicit. MxAsbDataClient exposes the MonitoredItem.Buffered flag through AddMonitoredItems, and MxAsbClient.Probe --subscribe-buffered sets it. A live buffered ASB publish probe against the historized TestMachine_001.TestHistoryValue succeeded, but returned the same single current MonitoredItemValue shape as the normal publish path: value 303, quality 0x00C0, timestamp 2026-04-26T02:33:45.4260000Z, and no multi-sample buffered batch.
  • ASB status mapping now includes installed MX detail 33 (WriteAccessDenied) and maps it to WriteFailedAccessDenied. Tests cover success, invalid monitored item, wrong-type write completion, invalid cleanup evidence inputs, request timeout detail 16, platform/no-communication detail 17, and access-denied detail 33.
  • Safe access-denied/no-communication candidate probes did not produce those source conditions on this VM. Same-value direct ASB writes to secured TestMachine_001.ProtectedValue and verified TestMachine_001.ProtectedValue1 both completed successfully and read back unchanged, so direct system-auth ASB writes do not reproduce the MXAccess public secured-write rejection path here. A read-only sweep of TestMachine_001.ProtectedValue through TestMachine_020.ProtectedValue registered and read all 20 values with good quality 0x00C0; no no-communication status was observed.
  • Native NMX completion-only operation-status handling is now stricter. One-byte completion-only frames remain preserved as raw, unpromoted completion statuses even when the byte is 0x00; only the observed 5-byte status-word frame 00 00 50 80 00 maps to MxStatus.WriteCompleteOk and can raise the MXAccess-compatible write-complete event. Tests cover completion-only 0x00, 0x41, and 0xEF, plus the promoted 0x8050/0x00 status-word frame. A search of the available Ghidra/decompiled outputs did not expose a completion-byte-to-MXSTATUS_PROXY[] mapping table beyond this public-event evidence.
  • Public ASB connection shaping has started. AsbConnectionOptions is now the stable options object for MxAsbDataClient.Connect, the previous string overload delegates to it, and MxAsbCompatibilityServer.Register has a matching options overload. Endpoint validation now happens before registry or WCF setup work. AsbPayloadDebug is no longer part of the public surface and is friend-only for the test/probe assemblies. A clean Release probe build, non-live ASB contract test run, and live read of TestChildObject.TestInt all passed after this change.
  • ASB write-completion options now validate their own polling/readback policy and expose a CancellationToken. Cancellation is checked before each PublishWriteComplete poll and during poll/readback delays; already-running synchronous ASB calls remain bounded by the existing WCF operation behavior. A live same-value write-completion probe still completed on the second poll for handle 0xA5B21001 and read back 412.
  • ASB subscription API shaping now has AsbSubscriptionOptions and AsbMonitoredItemOptions overloads while preserving the existing positional overloads. A live subscribe/publish probe created subscription 15, added monitored items for TestChildObject.TestInt and TestChildObject.TestString, published both mapped values/events, deleted the monitored items, deleted the subscription, and cleaned up the ASB connection successfully.
  • AsbPublishResult now exposes a derived Result summary and HasValues helper so callers do not have to remap raw PublishResponse.Result on every publish poll. The existing raw response and mapped values remain preserved.
  • Public API/request-shaping tests were expanded without live ASB dependency. They now pin defaults, validation, overload visibility, and helper DTO shape for connection, write completion/readback, subscription, monitored-item, compatibility Advise, and publish-result surfaces.
  • Basic writes now also have an AsbWriteOptions overload carrying the write handle and optional comment. The existing positional write overload and WriteInt32 path delegate through it, preserving behavior; a live same-value write-completion probe still completed on the second poll and read back 412.
  • Public multi-item APIs now explicitly reject null collection arguments before touching client state: RegisterMany, UnregisterMany, ReadMany, option-based AddMonitoredItems, and DeleteMonitoredItems. Empty collections and tag/item contents keep their prior behavior.
  • Published values and compatibility data-change events now expose derived StatusSummary helpers, and AsbResultMapper.ToItemSummaries maps nullable item-status arrays into raw-preserving summaries with null/empty as an empty result.
  • docs\ASB-Variant-Wire-Format.md now captures the supported ASB Variant wire format: type IDs, scalar and array payload layouts, timestamp/duration handling, string encoding, runtime value wrapping, quality/status payload parsing, and intentionally raw-preserved unsupported types.
  • docs\ASB-Native-Integration-Decision.md now records the recommended integration boundary: prefer MxAsbClient for the regular tag data plane behind a higher-level compatibility routing facade, keep MxNativeClient for native callback-only semantics and not-yet-proven MXAccess behaviors, and avoid merging ASB WCF lifecycle internals into the NMX DCE/RPC session.

Remaining Highest-Value Gaps

  1. Additional live faulted-channel and source-condition evidence that can be gathered safely. Current safe secured/verified-write and protected-value read sweeps did not produce access-denied or no-communication statuses.
  2. Broaden pure .NET 10 ASB only where safe source conditions expose new behavior. Local ASB Variant encode/decode, live reads/writes, subscription/create/add/publish/delete-monitored/delete-subscription, mapped publish events, compatibility data-change facade, options-shaped connection/write/subscription/advise/write-completion APIs, cleanup, and reconnect are now covered. Remaining work is mainly external failure modes such as access denied or no-communication when a safe source condition is available.
  3. A native runtime trigger for OperationComplete. The direct ASB path now proves a write-completion queue (PublishWriteComplete) carrying write handles and per-item statuses. Direct IASBIDataV2 does not expose activate/suspend or a generic operation-complete contract, and subscription create/add/publish/delete operations did not enqueue write-completion records. Map to MXAccess event ID 3 only if a separate native trigger is found.
  4. A native runtime/source condition that emits OnBufferedDataChange sample batches. Direct ASB buffered monitored items are accepted by this provider, but the observed publish response still carries one current value rather than a native MXAccess buffered sample batch.
  5. Exact mapping for completion-only operation-status bytes into MXSTATUS_PROXY[]; current code now preserves all completion-only bytes as unpromoted raw statuses instead of guessing, including completion-only 0x00.
  6. Cleanup behavior around live faulted/partial failure cases when a safe provider condition is available.
  7. Less-common ASB variant types only when real deployed tags expose them; the currently supported/proven variant layout is documented and unsupported declared types remain raw-preserved.

Treat the public ASB API-shaping sprint as closed unless a concrete caller gap appears. The remaining local documentation gaps are also closed. Return to exact completion-only operation-status mapping into MXSTATUS_PROXY[] only if a new safe native public-event capture or deeper targeted decompile can provide evidence. Keep live faulted-channel, access-denied, and source no-communication probes opportunistic unless a safe provider condition appears.