fe2a6db786
rust / build / test / clippy / fmt (push) Has been cancelled
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>
32 KiB
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 foraaMxDataConsumer.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.tcpIASBIDataV2channel, and live validates register, read, write, readback, published write completion, unregister parity, and multi-item register/read forTestChildObject.TestIntplusTestMachine_001.TestHistoryValue.MxAsbClient.Probe: clean Release build with zero warnings after adding an explicitSystem.Security.Cryptography.Xml10.0.7package reference and replacing the obsolete PBKDF2 constructor withRfc2898DeriveBytes.Pbkdf2.MxAsbClient.Tests: passed. The test project covers ASBVariantfactory 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,MonitoredItemValuebinary 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 forAsbConnectionOptions,AsbWriteOptions,AsbWriteCompletionOptions,AsbSubscriptionOptions, andAsbMonitoredItemOptions, DTO shape for write-completion/readback results, null collection argument guards, empty/non-emptyAsbPublishResulthelpers, derived status-summary helpers, item-status array mapping, and both compatibilityAdviseoverload signatures.- Credential scan over
analysis,docs,src,captures, andREADME.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, andSetBufferedUpdateInterval. - Public event families are represented:
OnDataChange,OnWriteComplete,OperationComplete, andOnBufferedDataChange. WriteSecured2is implemented and live validated from .NET 10 x64 for the observed authenticated secured-write body shape.WriteSecuredremains intentionally unsupported because installed MXAccess returns0x80004021for the observed secured/verified paths before emitting a value-bearing NMX body.- Object/VARIANT timestamp overloads exist for
Write2andWriteSecured2, matching the installed interop assembly's public API shape. SetHeartbeatSendIntervalis exposed and live validated throughMxNativeClient.Probe --probe-session-heartbeat --heartbeat-ticks=5 --heartbeat-max-missed=3.- Explicit recovery is implemented as
MxNativeSession.RecoverConnection()andMxNativeCompatibilityServer.RecoverConnection(serverHandle). The probe--probe-session-recover --tag=TestChildObject.TestInt --value=321live validated subscribe, recover, preserved subscription count, and write-through against local NmxSvc. RecoverConnectionAsyncadds a caller-controlled retry loop viaMxNativeRecoveryPolicy. Automatic write retry remains intentionally absent because it can duplicate writes.- Recovery lifecycle is observable through
RecoveryAttemptStarted,RecoveryAttemptFailed, andRecoveryCompletedon bothMxNativeSessionand the managed compatibility facade. A live recovery probe with--recover-attempts=2 --recover-delay-ms=100 --value=323observed 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-multireplays several active subscriptions and counts recovery-window callbacks by callback family.
Runtime Evidence Added In Latest Sprints
- GR identified
TestMachine_001.TestHistoryValueas a deployed, historized integer dynamic attribute. - Captures
121and122proved context-bearing buffered registration/result bodies forTestHistoryValue.property(buffer)in contextTestMachine_001. - Both supervisory and plain advise buffered captures still produced no native
Fire_OnBufferedDataChangeentry on this VM. - Reflection over
ArchestrA.MXAccess.dllconfirmed the 18-method public method surface, four event families,MxStatuslayout,MxStatusCategory,MxStatusSource, and fullMxDataTypeenum values. - Installed
Lmx.aaDCTdetail text has been folded intoMxStatusDetailsfor details16-61,541,542, and8017. - 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=trueon this VM. - A follow-up churn run with
--recover-concurrent-writeswroteTestChildObject.TestIntvalues330-334from a separate managed session during recovery. It preserved all four subscriptions and observed four data callbacks overall, including two withIsDuringRecovery=true. This validates the pass-through-with-marker callback policy under live traffic. aaMxDataConsumer.dllwas imported withtlbimpintoanalysis\interop\Interop.aaMxDataConsumer.dlland decompiled underanalysis\decompiled-interop\Interop.aaMxDataConsumer. Registry CLSID{85209FB2-0BA1-4594-BBC4-59D3DDAB823D}maps toMxDataConsumer Class.MxDataConsumerProbecan instantiateDataConsumerClass, registerIDataConsumerCallback, resolve namespace strings to namespace ID1, and callResolveReference,subscribe,ActivateSuspend, andProcessActivateSuspend2. However,IsConnected(namespaceId)remains0for tested namespace strings (Galaxy,ArchestrA,Lmx,localhost,ZB), no registration/subscription responses are produced, andProcessActivateSuspend2returns0x8007139F(ERROR_INVALID_STATE).DataClientClassappears in the importedaaMxDataConsumertype library, but its CLSID{73BC4121-FF89-4762-901C-206E2BD9FE87}is not registered on this node;MxDataConsumerProbe --probe-dataclientreports0x80040154(REGDB_E_CLASSNOTREG) before endpoint tests can run.- Headless/ILSpy analysis of
aaMxDataConsumer.dllshows the COM consumer is a mixed-mode wrapper around managed ASB data proxies.CDataClientCLIcreates aDataClientProxy, stores the namespace string, starts an auto-connect worker, andDataClientProxy.Initializepasses that same string asAccessNametoIDataProxySelector.SelectProxyForLatestEndpoint. ASBIDataV2Adapter.dllfrom the GAC containsIDataProxySelector. It first callsASBDataV2Proxy.FindIDataEndpoint(accessName, DiscoveryScope.Global); if that returns endpoints it constructsASBDataV2Proxy, otherwise it falls back to V1. The discovery scope isdomainname/<accessName>/global.AsbProxyProbelive x64 discovery found oneIASBIDataV2endpoint for access nameZB:net.tcp://desktop-6jl3kko/ASBService/Default_ZB_MxDataProvider/IDataV2. It found no endpoint forDefault_ZB_MxDataProvider,Galaxy,localhost, orZB2.AsbProxyProbe --access=ZB --connectopened the ASB data proxy from an x64 managed process.ASBDataV2Proxy.Connectreturnedtrue, channel state wasOpened, andPublishWriteCompletereturned0x00000000with 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.TestIntregistered and read the test integer throughIASBIDataV2.RegisterItemsandReadboth returned0x00000000; the item id was18446462598732840961; the read value was ASBDataType.TypeInt32(4) with payload4E010000, decoded as334.AsbProxyProbe --access=ZB --connect --register --read --write-int=401 --tag=TestChildObject.TestIntaccepted a basic ASB write and proved readback. The immediateWriteresult was globally successful, the per-item synchronous status was0x0000001F(ArchestrAError.OperationWouldBlock), the next read returned integer value401, andPublishWriteCompletethen returned0x00000020(ArchestrAError.PublishComplete) with the original write handle0xA5B20001and per-item completion status0x00000000. 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
MxDataConsumerProbeto--namespace=ZBhung in the COM wrapper path and was stopped. The direct ASB route is currently the cleaner path for x64 managed implementation and for any futureOperationCompletetrigger testing. - The pure .NET 10 ASB port in
src\MxAsbClientnow proves the live data path without loading AVEVA assemblies. Key auth details recovered during the port: this VM's ASB solution registry key isArchestra_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 forConnectionValidator,WriteValue,ItemStatus,ItemIdentity, andItemWriteComplete, plus mutable-struct-safe binary decode for nestedVariantandASBStatusvalues. MxAsbClient.Probe --tag=TestChildObject.TestInt --write-int=412completed from .NET 10 x64. The run read the previous value411, accepted write412with immediate per-item0x0000001F(OperationWouldBlock), read back412, and decodedPublishWriteCompleteresult0x00000020, count1, handle0xA5B21001, and final per-item status0x00000000.RegisterItemsparity is resolved for the observed startup race. ASBAuthenticateMeis a one-way WCF call; the first immediateRegisterItemscan arrive beforeASBIDataV2Shim.AuthenticateMeadds the connection implementation. The client now matches installed proxy signing for normal data calls and retriesRegisterItemsbriefly when the immediate result is0x00000001(InvalidConnectionId). Stage21 evidence shows first register message2returnedInvalidConnectionId, retry message3returned0x00000000with item id18446462598732840961, and later calls on the same connection succeeded.UnregisterItemsis implemented in the pure .NET 10 ASB port and compared against the installed AVEVAASBDataV2Proxy. Both clients return global success0x00000000and the same per-item0x0000000B(OperationFailed) for the registeredTestChildObject.TestIntidentity on this provider. Evidence:analysis\proxy\mxasbclient-probe-stage23-unregister-id.txtandanalysis\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.txtregisters and readsTestChildObject.TestIntandTestMachine_001.TestHistoryValuein single two-item requests. Both register and read return global0x00000000and per-item0x00000000; the read values decode as ASBTypeInt32with previews412and303. - The pure .NET 10 ASB port now has non-live ASB
Variantconstruction 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 genericWrite(tag, Variant, writeHandle)path so the next live write probes can reuse the same encoder instead of being hard-coded toInt32. - 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 matchingTestBoolArray[],TestIntArray[],TestFloatArray[],TestDoubleArray[],TestStringArray[], andTestDateTimeArray[]returning ASB array types57,44,48,49,50, and51. All register/read per-item statuses were0x00000000, and previews decoded correctly. MxAsbClient.Probenow 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:TestBoolaccepted aTypeBoolwrite and later read backFalsethenTrue;TestFloatwrote/read13.25;TestDoublewrote/read13.75;TestStringacceptedasb-scalar-writeand read it back on a delayed follow-up read;TestDateTimewrote/read2026-04-26T14:33:00Z. These runs confirm the scalar factory payloads are accepted by the live provider. ImmediatePublishWriteCompleteoften returned count0, 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 back11-20;TestBoolArray[]accepted/read back alternating false/true values;TestFloatArray[]andTestDoubleArray[]accepted/read back11.1-20.1;TestStringArray[]accepted/read backK11-T20; andTestDateTimeArray[]accepted/read back ten UTC timestamps from2026-04-26T14:40:00Zthrough2026-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.Xml10.0.0package is overridden with10.0.7,dotnet list package --include-transitive --vulnerablenow reports no vulnerable packages forMxAsbClient, 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 ofTestChildObject.TestIntstill succeeds after the authenticator change. - Pure .NET 10 ASB subscription/publish is now live-proven for the basic
lifecycle.
MxAsbClient.Probe --subscribe --publish-count=3created subscription id3, added monitored items forTestChildObject.TestIntandTestChildObject.TestStringwith per-item status0x00000000, received both values on the second publish poll (TypeInt32preview412andTypeStringpreviewasb-scalar-write), deleted the subscription with global success, and then completed the existing unregister cleanup path. Publish responses returned global0x00000020, matching the previously observed completion queue success signal, so exact result/status mapping remains open. - The ASB publish path now maps raw
MonitoredItemValueresponses 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 forTestChildObject.TestIntandTestChildObject.TestStringdecoded quality0x00C0and status elementsOpcUaStatus:0|OpcUaVendorStatus:0|MxStatusCategory:0|MxStatusDetail:0|MxQuality:192for both values. The same run addedDeleteMonitoredItems, returned global success and per-item0x00000000for both monitored identities, then deleted the subscription successfully. MxAsbDataClientnow exposesPublishedValueReceivedplusPublishValues.PublishValueskeeps the rawPublishResponse, maps values through the client's monitored-item id cache, and raises one event per mapped value. A live probe observedpublished_event[0]forTestChildObject.TestIntandpublished_event[1]forTestChildObject.TestString, both with quality0x00C0and expected previews.MxAsbCompatibilityServernow adapts the pure ASB stream into an MXAccess-like server/item-handle data-change facade. A liveMxAsbClient.Probe --compat-subscribe --publish-count=3run registered ASB server handle1, added/advised item handles1and2, polled publish, raised twocompat_data_changeevents with values412andasb-scalar-write, quality0x00C0, decoded ASB status elements, removed both monitored items, and unregistered cleanly.- The compatibility facade now has an
Adviseoverload that acceptsAsbSubscriptionOptionsplusAsbMonitoredItemOptions, 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 mappedcompat_data_changeevents, removed monitored items, and unregistered cleanly. - Initial non-success ASB item-status mapping is implemented. A live probe for
DefinitelyMissingObject.DefinitelyMissingAttributeshowed global register and read success but per-item read error0x000A(InvalidMonitoredItems), an empty value with value-status payload decoded asOpcUaStatus:32905|OpcUaVendorStatus:0|MxStatusCategory:750|MxStatusDetail:0|MxQuality:0, and unregister per-item error0x000B(OperationFailed). Unknown payloads are still preserved rather than guessed. MxAsbClient.Probe --probe-error-casesnow keeps broader live ASB non-success evidence opt-in without changing production client behavior. Evidence inanalysis\proxy\mxasbclient-probe-error-cases-v2.txtcovers: invalid read target global success with per-item0x000A(InvalidMonitoredItems) plus bad value status; invalid-target async write immediate per-item0x001F(OperationWouldBlock) followed byPublishWriteCompleteglobal0x0020(PublishComplete) and completion per-item0x0006(MonitoredItemsNotFound) with status payloadOpcUaStatus:6|OpcUaVendorStatus:0|MxStatusCategory:4|MxStatusDetail:6; wrong-type string write toTestChildObject.TestIntimmediate per-item0x001F, completion per-item0x0013(WriteFailedBadTypeMismatch) with status payloadOpcUaStatus:19|OpcUaVendorStatus:0|MxStatusCategory:4|MxStatusDetail:8001, and unchanged readback value412; invalid monitored-item cleanup global success with per-item0x000B(OperationFailed); invalid subscription delete global0x000C, status0x0020, specific0x80020000; and empty subscription publish returning global0x0020with no values.- ASB result/status summaries now name the full installed
ArchestrAErrorcode set, classify publish0x0020(PublishComplete) as success-like for publish polling, summarizeMxQualityas good/uncertain/bad/unknown, and map known MX status details16and17toRequestTimedOutandBadNoCommunicationwhile preserving raw category/detail/quality values. - Async ASB write completion now has a production-oriented polling helper.
WaitForWriteCompletepollsPublishWriteCompletefor a target write handle until completion or timeout, preserving every raw poll response and completion record.WaitForWriteCompleteAndReadadds 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=500saw the first completion poll return count0, the second poll return the matching handle0xA5B21001, and readback return412. - ASB client disposal now has explicit cleanup reporting.
Dispose()delegates to idempotentCleanup(), sends signedDisconnectbest-effort, closes the channel and factory independently, aborts safely after close/fault failures, and recordsLastCleanupResultwithCompleted,Succeeded,UsedAbortFallback, andRequiresNewConnection. A live read probe ended withasb.stage=cleanup,asb.stage=disconnect, andasb.cleanup.succeeded=True. - ASB reconnect now has an explicit opt-in API.
MxAsbDataClient.Reconnectvalidates 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 liveMxAsbClient.Probe --probe-reconnect --reconnect-attempts=2 --reconnect-delay-ms=250 --cleanup-disconnect-timeout-ms=5000 --cleanup-close-timeout-ms=5000run readTestChildObject.TestIntas412, cleaned up and disconnected the original connection with caller cleanup timeouts, connected successfully on attempt1, re-registered the tag on the new client, read back412, 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.
AsbClientCleanupOptionsaccepts aCancellationToken; 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 liveMxAsbClient.Probe --probe-canceled-cleanuprun connected, registered, and readTestChildObject.TestIntas412, then skipped disconnect and aborted both opened communication objects locally. The cleanup result completed withsucceeded=False,abort=True,requires_new=True, and anOperationCanceledExceptiondisconnect 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/IDataV2reportsconnect_failure_observed=True, anEndpointNotFoundException, and innerSocketException10061for a refused local TCP endpoint.Connectnow also closes or aborts any WCF channel/factory objects created before a connection setup failure; the refused-endpoint probe reportsasb.stage=connect-cleanupbefore surfacing the exception. - OperationComplete candidate evidence was narrowed on the direct ASB route.
The
IASBIDataV2contract exposed by the live endpoint has no activate, suspend, or generic operation-complete operation; onlyPublishWriteCompleteexists, and it is write-specific. A liveMxAsbClient.Probe --probe-operation-complete-candidatesrun againstTestChildObject.TestIntandTestChildObject.TestStringpolledPublishWriteCompletebefore and after create-subscription, add-monitored, publish, delete-monitored, and delete-subscription operations. Every poll returned count0, while the non-write operations themselves succeeded. - ASB buffered-subscription probing is now explicit.
MxAsbDataClientexposes theMonitoredItem.Bufferedflag throughAddMonitoredItems, andMxAsbClient.Probe --subscribe-bufferedsets it. A live buffered ASB publish probe against the historizedTestMachine_001.TestHistoryValuesucceeded, but returned the same single currentMonitoredItemValueshape as the normal publish path: value303, quality0x00C0, timestamp2026-04-26T02:33:45.4260000Z, and no multi-sample buffered batch. - ASB status mapping now includes installed MX detail
33(WriteAccessDenied) and maps it toWriteFailedAccessDenied. Tests cover success, invalid monitored item, wrong-type write completion, invalid cleanup evidence inputs, request timeout detail16, platform/no-communication detail17, and access-denied detail33. - 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.ProtectedValueand verifiedTestMachine_001.ProtectedValue1both 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 ofTestMachine_001.ProtectedValuethroughTestMachine_020.ProtectedValueregistered and read all 20 values with good quality0x00C0; 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 frame00 00 50 80 00maps toMxStatus.WriteCompleteOkand can raise the MXAccess-compatible write-complete event. Tests cover completion-only0x00,0x41, and0xEF, plus the promoted0x8050/0x00status-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.
AsbConnectionOptionsis now the stable options object forMxAsbDataClient.Connect, the previous string overload delegates to it, andMxAsbCompatibilityServer.Registerhas a matching options overload. Endpoint validation now happens before registry or WCF setup work.AsbPayloadDebugis 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 ofTestChildObject.TestIntall passed after this change. - ASB write-completion options now validate their own polling/readback policy
and expose a
CancellationToken. Cancellation is checked before eachPublishWriteCompletepoll 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 handle0xA5B21001and read back412. - ASB subscription API shaping now has
AsbSubscriptionOptionsandAsbMonitoredItemOptionsoverloads while preserving the existing positional overloads. A live subscribe/publish probe created subscription15, added monitored items forTestChildObject.TestIntandTestChildObject.TestString, published both mapped values/events, deleted the monitored items, deleted the subscription, and cleaned up the ASB connection successfully. AsbPublishResultnow exposes a derivedResultsummary andHasValueshelper so callers do not have to remap rawPublishResponse.Resulton 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
AsbWriteOptionsoverload carrying the write handle and optional comment. The existing positional write overload andWriteInt32path delegate through it, preserving behavior; a live same-value write-completion probe still completed on the second poll and read back412. - Public multi-item APIs now explicitly reject null collection arguments before
touching client state:
RegisterMany,UnregisterMany,ReadMany, option-basedAddMonitoredItems, andDeleteMonitoredItems. Empty collections and tag/item contents keep their prior behavior. - Published values and compatibility data-change events now expose derived
StatusSummaryhelpers, andAsbResultMapper.ToItemSummariesmaps nullable item-status arrays into raw-preserving summaries with null/empty as an empty result. docs\ASB-Variant-Wire-Format.mdnow captures the supported ASBVariantwire 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.mdnow records the recommended integration boundary: preferMxAsbClientfor the regular tag data plane behind a higher-level compatibility routing facade, keepMxNativeClientfor 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
- 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.
- Broaden pure .NET 10 ASB only where safe source conditions expose new
behavior. Local ASB
Variantencode/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. - A native runtime trigger for
OperationComplete. The direct ASB path now proves a write-completion queue (PublishWriteComplete) carrying write handles and per-item statuses. DirectIASBIDataV2does 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 ID3only if a separate native trigger is found. - A native runtime/source condition that emits
OnBufferedDataChangesample 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. - 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-only0x00. - Cleanup behavior around live faulted/partial failure cases when a safe provider condition is available.
- 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.
Recommended Next Sprint
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.