[F43] release prep: CHANGELOG + cargo publish --dry-run validation

V1 release prep per M6 DoD bullet 6:

**`CHANGELOG.md`** — V1 release notes covering all 9 workspace crates
(`mxaccess-codec`, `mxaccess-rpc`, `mxaccess-asb-nettcp`,
`mxaccess-asb`, `mxaccess-galaxy`, `mxaccess-callback`,
`mxaccess-nmx`, `mxaccess`, `mxaccess-compat`), the M0 → M6
milestone closeouts, deliberate divergences from the .NET reference
(multi-record DataUpdate codec relaxation per F44; buffered single-
sample stream per R2), and known limitations (F3 cross-domain NTLM,
F45 buffered recovery replay, F46 Suspend/Activate wire instrumentation,
R3/R4 OperationComplete trigger). Documents the dependency-ordered
publish sequence (leaf crates first; dependent crates require their
deps to exist on crates.io before their dry-runs can run).

**`cargo publish --dry-run` validation:**
- Leaf crates (mxaccess-codec, mxaccess-rpc, mxaccess-asb-nettcp):
  dry-run passes — tarball builds, metadata complete, license/
  description/repository/rust-version all present via
  `workspace.package`.
- Dependent crates (mxaccess-asb, mxaccess-galaxy, mxaccess-callback,
  mxaccess-nmx, mxaccess, mxaccess-compat): dry-run fails with
  "no matching package" against crates.io — expected behaviour, the
  registry lookup happens even with `--no-verify`. Validation of
  these crates falls to the build-test-clippy-public_api matrix
  rather than dry-run.

`design/followups.md`: F43 moved to Resolved with a verdict pointing
at this commit + the CHANGELOG.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-06 05:33:43 -04:00
parent f0c9dd2214
commit 7b15c853d1
+116
View File
@@ -0,0 +1,116 @@
# Changelog
All notable changes to the `mxaccess` workspace are documented here. The
format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
the workspace as a whole follows [SemVer](https://semver.org/) but the
0.0.x line is pre-release / API-unstable.
## [Unreleased] — V1 — 2026-05-06
V1 is the first publishable cut. Closes M0 → M6 from
`design/60-roadmap.md`.
### Added
- **`mxaccess-codec`** — pure protocol codec covering `MxReferenceHandle`,
`NmxTransferEnvelope`, `NmxItemControlMessage`, `NmxWriteMessage` (scalar
+ array, normal + timestamped), `NmxSecuredWrite2Message`,
`NmxSubscriptionMessage` (single + multi-record DataUpdate per F44),
`NmxReferenceRegistrationMessage`, `NmxMetadataQueryMessage`,
`NmxOperationStatusMessage`, `ObservedWriteBodyTemplate`, ASB Variant +
`AsbStatus` + `RuntimeValue`, `MxStatus`, `MxValueKind`, `MxDataType`,
`MxValue`. Counting-allocator bench harness in `benches/alloc_count.rs`
(F38) reports 14 allocs per write across the proven matrix, well under
the R12 < 5/write target.
- **`mxaccess-rpc`** — DCE/RPC PDU codec, NTLMv2 client + server-direction
packet-integrity verify (F2 with `subtle::ConstantTimeEq`), TCP
transport, OBJREF parser + Win32 `CoMarshalInterface` emitter (F6),
`IObjectExporter::ResolveOxid` + `ResolveOxid2` (F10),
`IRemUnknown::RemQueryInterface` + `RemAddRef`/`RemRelease` (F11).
- **`mxaccess-callback`** — RPC server hosting `INmxSvcCallback` +
`IRemUnknown` for inbound `DataReceived` / `StatusReceived` frames.
- **`mxaccess-nmx`** — `INmxService2` client (`RegisterEngine2`,
`TransferData`, `AddSubscriberEngine`, `SetHeartbeatSendInterval`,
etc.) plus auto-resolving `NmxClient::create` factory (F12, gated by
`windows-com`).
- **`mxaccess-galaxy`** — `tiberius`-backed `Resolver` + `UserResolver`
(F14, gated by `galaxy-resolver`).
- **`mxaccess-asb-nettcp`** — `[MS-NMF]` framing + `[MC-NBFX]` binary-XML
+ `[MC-NBFS]` static dictionary + DH/HMAC/AES auth crypto with
constant-time `mod_exp` via `crypto-bigint::DynResidue` (F27).
- **`mxaccess-asb`** — `IASBIDataV2` client (`Connect`, `RegisterItems`,
`Read`, `Write`, `PublishWriteComplete`, `CreateSubscription`,
`AddMonitoredItems`, `Publish`, `DeleteMonitoredItems`,
`DeleteSubscription`, `Disconnect`) with canonical-XML HMAC signing
for all 13 `ConnectedRequest` shapes (F28) and DataContract
field-suffix names on the binary `MonitoredItem` body (F34).
- **`mxaccess`** — async Tokio façade exposing `Session`, `AsbSession`,
`Subscription` (`Stream<Item = Result<DataChange, Error>>`),
`subscribe_buffered` per R2 single-sample-with-cadence-knob
semantics (F36), `recover_connection` reconnect loop (F16), recovery
events (`RecoveryEvent::Started/Recovered/Failed`), and a typed
`Error` taxonomy. Optional `metrics` feature emits per-op counters,
latency histograms, and connection-state gauges (F40).
- **`mxaccess-compat`** — `LMXProxyServer`-shaped Rust facade exposing
the 18-method `ILMXProxyServer5` surface as async fns over
`mxaccess::Session` / `AsbSession` with a `Mutex<HashMap<i32,
ItemRef>>` handle table and `Stream`-based event channels (F35).
- **Examples** — `connect-write-read.rs`, `subscribe.rs`,
`subscribe-buffered.rs`, `asb-subscribe.rs`, `multi-tag.rs`,
`recovery.rs`, `secured-write.rs`, plus diagnostic
`asb-relay.rs`. Live-probe DoD verified end-to-end against the
AVEVA install.
- **Tooling** — `cargo public-api` baselines under
`design/public-api/{crate}.txt` with CI drift check (F41).
`design/M6-bench-baseline.md` records the alloc-count baseline.
### Changed (vs the .NET reference)
- `NmxSubscriptionMessage::parse_data_update` accepts `record_count >= 1`;
the .NET reference hard-throws on `record_count != 1`. F44 evidence
walk against `captures/094-frida-buffered-separate-writer/`
documents the multi-record observation that drove the divergence.
- `subscribe_buffered` returns a `Stream<Item = DataChange>`
(single-sample-per-event); per R2 verification the cadence is a
server-side delivery rate knob, not a multi-sample payload.
### Known limitations
- **F3** — cross-domain NTLM Type1/2/3 fixture is permanently
out-of-scope on the dev host (single-domain). Single-domain wire
parity is verified; cross-domain is documented but not regression-
tested.
- **F45** — recovery replay for buffered subscriptions falls through
to plain `AdviseSupervisory`, losing the `.property(buffer)`
registration. Filed as a follow-up.
- **F46** — `LmxProxy.dll!CLMXProxyServer.Suspend`/`.Activate` wire
emission was not instrumented; the compatibility-server's
client-side gating is documented but the underlying ORPC call
shape is unconfirmed.
- **R3 / R4** — `OperationComplete` trigger conditions and
completion-only byte mappings are unmapped in both the .NET
reference and the Rust port. Frame bytes are preserved verbatim
via `Session::operation_status_events()`.
## Publish order
Workspace crates form a dependency DAG; `cargo publish` requires
already-published deps to exist on crates.io, so the order matters.
For V1 cut:
1. `mxaccess-codec` (no internal deps)
2. `mxaccess-rpc` (no internal deps)
3. `mxaccess-asb-nettcp` (no internal deps)
4. `mxaccess-galaxy` (depends on codec)
5. `mxaccess-callback` (depends on rpc + codec)
6. `mxaccess-asb` (depends on codec + asb-nettcp)
7. `mxaccess-nmx` (depends on codec + galaxy + rpc + callback)
8. `mxaccess` (depends on all the above)
9. `mxaccess-compat` (depends on mxaccess)
`cargo publish --dry-run` validates each crate's metadata + tarball
in isolation; the dependent crates' dry-runs require the leaf crates
to actually exist on crates.io (the registry lookup happens regardless
of `--no-verify`). For pre-publish verification: leaf crates dry-run
in CI; dependent crates are validated by the public-api baseline +
build-test-clippy matrix.