**F41 — public-api baselines (M6 DoD bullet 5)**
`design/public-api/{crate}.txt` for all 9 workspace crates, generated
via `cargo +nightly public-api --simplified -p <crate>`. Per-crate
baseline sizes:
- mxaccess-codec: 2516 lines
- mxaccess-asb: 1258 lines
- mxaccess-rpc: 1273 lines
- mxaccess-asb-nettcp: 708 lines
- mxaccess: 542 lines
- mxaccess-galaxy: 374 lines
- mxaccess-callback: 170 lines
- mxaccess-compat: 123 lines
- mxaccess-nmx: 118 lines
`design/public-api/README.md` documents the update procedure
(install nightly + cargo-public-api, regenerate the affected baseline
on intentional API changes, commit alongside).
`.github/workflows/rust.yml` gains a `public-api` job that runs the
same diff against the committed baseline; drift fails CI with a
unified diff in the log so the PR author can either revert or
update the baseline.
**F44 reconciliation — multi-record DataUpdate codec**
Cherry-picked from the F44 sub-agent's worktree (commit `aec6a0c`):
`subscription_message.rs::parse_data_update` now loops over
`record_count` like `parse_subscription_status` does, accepting any
positive count. The .NET reference still hard-throws on
`record_count != 1`; the Rust codec deliberately diverges per the F44
evidence walk against `captures/094-frida-buffered-separate-writer/
frida-events.tsv:145` (a `0x33` DataUpdate body with `record_count = 2`,
inner_length = 23 (preamble) + 2 * 19 (records) = 61, post a
separate-session writer triggering two value changes inside one
`SetBufferedUpdateInterval(1000)` window).
Two new round-trip tests:
- `data_update_multi_record_round_trip` — synthesises a 2-record body,
parses, asserts both records decode to expected Int32 values.
- `data_update_capture_094_truncated_record_errors` — truncates the
capture-094 fixture mid-second-record, asserts CodecError::Decode.
New wire-byte fixtures under `crates/mxaccess-codec/tests/fixtures/m6-buffered/`:
- `094-line145-dataupdate-recordcount2.bin` (57 bytes, `0x33` multi-record)
- `094-line48-substatus-recordcount2.bin` (101 bytes, `0x32` multi-record)
R2 in `design/70-risks-and-open-questions.md` updated from
"single-sample (settled silently)" to "settled per option (a) — codec
relaxed; multi-record observed in production-stack tracing."
`design/followups.md`: F44's verdict updated to reflect the
contradiction-then-relaxation, with reference to the new tests +
fixtures.
Workspace 792 → 794 tests pass; clippy clean; rustdoc clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
design/ — Rust port architectural plan
This folder is the design contract for the Rust replacement of AVEVA/Wonderware MXAccess. It is the gap between the .NET reference in src/ and the Rust crates that will be written under a sibling rust/ workspace (per CLAUDE.md).
The folder is structured as a small set of focused documents. Read in order; each builds on the previous.
| File | Purpose |
|---|---|
00-overview.md |
Mission, two-layer goal, architectural principles, non-goals |
10-raw-layer.md |
Byte-accurate raw MXAccess layer (codec + transport + session) |
20-async-layer.md |
Idiomatic Tokio async layer on top of the raw layer |
30-crate-topology.md |
Cargo workspace, crates, dependencies, build/test commands |
40-protocol-invariants.md |
Bill of materials: IIDs, opnums, envelope/handle bytes |
50-error-model.md |
MxStatus, error types, panic/cancellation policy |
60-roadmap.md |
Milestones M0..M6, validation strategy |
70-risks-and-open-questions.md |
Parity gaps, unproven flows, cross-platform constraints |
dependencies.md |
Cross- and within-milestone parallelism map; agent budget per phase |
review.md |
Adversarial review log (BLOCKER/MAJOR/MINOR/NIT findings, all resolved) |
prompt.md |
/loop driver prompt for autonomous M2–M6 execution |
followups.md |
Open / resolved deferred work items; auto-triaged by prompt.md Step 0 (created on first /loop run if missing) |
The design is grounded in the .NET reference at src/ and the protocol artifacts in docs/, analysis/, and captures/. Do not introduce protocol behavior in these documents that is not already proven in the reference. When adding a new claim about wire format, cite either:
- a
.csfile path insrc/MxNativeCodec/,src/MxNativeClient/, orsrc/MxAsbClient/, or - a
docs/*.mdspec file, or - a
captures/0NN-frida-*directory oranalysis/frida/*.tsvrow.
This folder is documentation, not code. When the Rust workspace is created, the design here is the contract it must satisfy. When evidence in captures/ invalidates a design decision here, update the design first, then the code.
Reading order
- New contributor: 00 → 30 → 10 → 40 → 20 → 50 → 60 → 70.
- Protocol question: 40 first, then the relevant section of 10.
- API question: 20 first, then 50.
- Planning a milestone: 60 first, cross-reference 70 for blockers.
- Scheduling concurrent work:
dependencies.mdfor the per-phase parallelism map. - Driving M2–M6 autonomously via
/loop:prompt.md(and thefollowups.mdtriage log it maintains).