diff --git a/design/followups.md b/design/followups.md index a4a0527..b549d4d 100644 --- a/design/followups.md +++ b/design/followups.md @@ -6,6 +6,93 @@ move to `## Resolved` with a date + commit hash. ## Open +### F48 — Execute `cargo publish` for the V1 release cut +**Severity:** P1 — V1 release driver. F43 only validated dry-run for the leaf crates; the actual publish to crates.io has not happened. +**Source:** `design/60-roadmap.md:100` (M6 DoD bullet 6 — "Release: cargo publish all crates"); `CHANGELOG.md` "Publish order" section. +**Depends on:** F43 (dry-run validation), F49 (live verification of M6 features before publishing them). + +**Scope.** Publish all 9 workspace crates to crates.io in dependency order: +1. `mxaccess-codec`, 2. `mxaccess-rpc`, 3. `mxaccess-asb-nettcp` (leaves — no internal deps) +4. `mxaccess-galaxy`, 5. `mxaccess-callback`, 6. `mxaccess-asb` (single-internal-dep tier) +7. `mxaccess-nmx`, 8. `mxaccess`, 9. `mxaccess-compat` (multi-internal-dep tier) + +Between each publish: wait for the crate to be indexed before the next one's `cargo publish` runs (the registry-lookup race that broke the dependent dry-runs in F43). + +**Definition of done:** +1. All 9 crates exist on crates.io at the same workspace version (likely 0.1.0 — bump from the 0.0.0 placeholder before the cut). +2. `cargo install mxaccess` resolves a clean dependency tree from a fresh registry lookup (no `--locked` workaround). +3. Tag the V1 release commit (`git tag v0.1.0`) and push the tag so the CHANGELOG anchors to a stable ref. + +**Resolves when:** crates.io shows all 9 crates published + the V1 tag is pushed. + +### F49 — Live verification sweep for the M6 features +**Severity:** P1 — closes the live-evidence gap for the M6 work that landed unit-only this session. +**Source:** F36, F40, F45, F47 closeouts — each ships with unit tests but several were not exercised against the live AVEVA install in this session. + +**Scope.** Run the following against the live AVEVA host with `MX_LIVE=1`: +1. **F36 buffered subscribe** — `cargo run -p mxaccess --example subscribe-buffered -- --tag TestChildObject.TestInt`. Confirm `OnBufferedDataChange`-rate updates flow at the configured cadence; capture wire bytes via `analysis/frida/mx-nmx-trace.js` and confirm exactly one `RegisterReference` (`0x10`) frame with `.property(buffer)` suffix, no separate `SetBufferedUpdateInterval` RPC, and no separate `AdviseSupervisory` follow-up. +2. **F45 recovery replay for buffered** — start the `subscribe-buffered` example, force a `Session::recover_connection` mid-flight (e.g. via a `wwtools` helper that bumps the NMX TCP socket), assert the post-recovery NMX traffic carries an `RegisterReference` (NOT `AdviseSupervisory`) with the same correlation id and `.property(buffer)` suffix. +3. **F47 buffered unsubscribe skip** — instrument `Session::unsubscribe` with a `tracing::debug` log line on the buffered branch, run the example to completion + drop, confirm no `UnAdvise` frame in the wire trace. +4. **F40 metrics** — install a `metrics` exporter (`metrics-exporter-prometheus` is the lightest), run `connect-write-read` + `subscribe` examples with `--features metrics`, confirm at least one counter increment and one histogram observation per metric name in the registered set. + +**Definition of done:** +1. Per-feature evidence summary in `docs/M6-live-verification.md` (one paragraph per feature with the wire-trace excerpt or metrics-exporter snapshot). +2. If any feature fails live: file a sub-followup with the captured failure and link it from the evidence doc. + +**Resolves when:** all four features have a live evidence row + no sub-followups remain unresolved. + +### F50 — Run the F46 Suspend/Activate Frida capture live +**Severity:** P3 — residual from F46 (script ready, capture not yet run). +**Source:** F46 closeout (`design/followups.md`) + `analysis/frida/mx-nmx-trace.js` header procedure. + +**Scope.** Run the Frida script against a live `MxTraceHarness.exe` exercising the suspend-advised + activate-advised scenarios on `TestChildObject.ScanState`. Save under `captures/NNN-frida-suspend-activate-instrumented/`. If the new `mx.suspend.*` / `mx.activate.*` events accompany NMX traffic in the same time window: document the wire opnum + body shape in `docs/M6-buffered-evidence.md` and `analysis/proxy/nmxsvcps-procedures.tsv`. If no NMX traffic accompanies the hook fires: update `design/70-risks-and-open-questions.md` R5 to "settled — client-side only". + +**Definition of done:** R5 is fully settled (either with a documented wire opnum or a "client-side only" verdict backed by capture). + +**Resolves when:** the capture lands and R5's status is updated. + +### F51 — Live type-matrix expansion for the ASB Variant codec (`asb-subscribe`) +**Severity:** P2 — F32 was closed via "deployable maximum" interpretation (only Int32 verified live), but the codec supports Bool / Float / Double / String / DateTime / Duration / arrays without live evidence. +**Source:** F32 closeout (`design/followups.md`); `work_remain.md:108-113` documents the proven matrix from .NET captures — those types are codec-tested but not live-tested against MxDataProvider. + +**Scope.** Provision sample tags on the local Galaxy for each missing type (Bool, Float, Double, String, DateTime, Duration, plus 1-2 representative array shapes). Extend `examples/asb-subscribe.rs` with a per-type loop that registers + reads + subscribes against each. Capture the wire bytes via `examples/asb-relay.rs` middleman and add round-trip parity tests in `crates/mxaccess-asb/tests/` for each type. + +**Definition of done:** +1. Per-type Galaxy fixture documented in `docs/galaxy-test-fixtures.md` (which child object names to provision, expected attribute types). +2. `cargo run -p mxaccess --example asb-subscribe -- --type-matrix` exercises all proven types and reports per-type wire bytes + decoded value. +3. Round-trip test per type in `crates/mxaccess-asb/tests/` pinning the captured wire bytes. + +**Resolves when:** every proven type from `work_remain.md:108-113` has a live wire fixture + a passing round-trip test. + +### F52 — Codec performance optimisations deferred from F39 +**Severity:** P3 — R12 < 5 allocs/write target is already met; these are nice-to-haves. +**Source:** `design/M6-bench-baseline.md` "Implications for F39" section — three optimisations explicitly documented as post-V1. + +**Scope.** Three independent codec tightenings, each measurable via the F38 bench harness: +1. **`bytes::BytesMut` output buffer** on the encoder side. Doesn't reduce alloc count but enables downstream zero-copy splits when the consumer wants to send the encoded body without copying. +2. **Per-handle name-signature cache** in `MxReferenceHandle::from_names`. Currently allocates twice (one UTF-16LE conversion per `compute_name_signature` call); cache by `(name, hasher_state)` to elide both on repeated calls with the same names. +3. **Session-level scratch pool** for the per-write encode buffer. Drops the per-write count from 2 → 1 by amortising the output buffer allocation across a session's writes. + +**Definition of done:** +1. Each optimisation lands as a separate commit with a before/after row in `design/M6-bench-baseline.md` showing the alloc-count delta. +2. No correctness regressions in the round-trip fixture suite. +3. Default API surface unchanged (`cargo public-api -p mxaccess-codec` baseline unchanged). + +**Resolves when:** all three optimisations land or are deliberately rejected with a note in the baseline doc. + +### F53 — Enable `#![warn(missing_docs)]` workspace-wide +**Severity:** P3 — doc-coverage tightening; not a correctness or release blocker. +**Source:** F42 closeout — the missing-docs lint was deferred because enabling it surfaces hundreds of low-priority public-item gaps that are out of scope for that F-number. + +**Scope.** Per crate root, add `#![warn(missing_docs)]` (or `#![deny(missing_docs)]` for the consumer-facing `mxaccess` + `mxaccess-compat`). Then walk each warning and add at minimum a one-line doc comment per public item. Strategy: do the consumer-facing crates first (`mxaccess`, `mxaccess-compat`); the protocol crates (`mxaccess-codec`, `mxaccess-rpc`, etc.) can land later since their consumers are the higher-level crates which already document the surfaces they re-export. + +**Definition of done:** +1. `RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps` continues to pass with the lints enabled. +2. Every public item in `mxaccess` + `mxaccess-compat` has at least a one-line doc comment. +3. Protocol crates either get the lint enabled too or have an inline `#[allow(missing_docs)]` with a reason that points at this followup. + +**Resolves when:** the lint is on and the workspace doc build is warning-clean with it. + ### F3 — Cross-domain NTLM Type1/2/3 fixture **Severity:** P2 **Status:** Permanently out-of-scope on the current dev host (no second AD domain). Resolution requires external infrastructure not available here.