diff --git a/design/followups.md b/design/followups.md index 0c81790..517711e 100644 --- a/design/followups.md +++ b/design/followups.md @@ -58,50 +58,6 @@ move to `## Resolved` with a date + commit hash. **Resolves when:** `cargo run -p mxaccess --example subscribe-buffered` runs against AVEVA and the live captures `079`/`082` byte-round-trip via the new code path. -### F37 — ASB `subscribe_buffered` capability gate -**Severity:** P3 — small wiring item; M5 already documented `Error::Unsupported(SubscribeBuffered)` as the intended ASB shape (`design/60-roadmap.md:88`). -**Source:** `design/60-roadmap.md:88` + F18 closeout block. - -**Scope.** Wire `AsbSession::subscribe_buffered` (and the equivalent on the `mxaccess::Session` ASB-transport variant if the API converges) to return `Error::Unsupported(Capability::SubscribeBuffered)` synchronously. ASB does not have a buffered-cadence equivalent — the per-monitored-item `SampleInterval` already plays that role. - -**Definition of done:** -1. Calling `subscribe_buffered` against an ASB-backed session returns `Error::Unsupported(Capability::SubscribeBuffered)` without touching the wire. -2. Unit test asserts the error variant + capability discriminant. -3. Doc on the method explains the ASB asymmetry (per-monitored-item `SampleInterval` is the buffered-cadence analogue, callers should use `MinimalMonitoredItem.sample_interval` instead). - -**Resolves when:** F36 has the NMX path landed and the same call signature on ASB returns the typed `Unsupported` error. - -### F38 — Counting-allocator `cargo bench` harness -**Severity:** P1 — blocks M6 DoD bullet 3 (per-write allocation target measurable) and F39 (zero-copy pass needs the harness to verify). -**Source:** `design/60-roadmap.md:102` + `design/70-risks-and-open-questions.md` R12. - -**Scope.** Add a `cargo bench` setup under `crates/mxaccess-codec/benches/` (and possibly `mxaccess/benches/`) that wraps the global allocator with a counting allocator (e.g. `dhat` or a hand-rolled `GlobalAlloc` impl) and reports per-operation allocation counts for the proven matrix: -- write encode (Int32 / Float / Double / String / Bool) -- subscribe decode (DataUpdate single-record) -- ASB ConnectedRequest envelope encode (RegisterItems + AddMonitoredItems) - -Print baseline numbers in a CSV/markdown table committed to `design/` so future PRs can diff against it. - -**Definition of done:** -1. `cargo bench -p mxaccess-codec` runs on Windows + measures alloc counts for the proven matrix. -2. Baseline numbers committed to `design/M6-bench-baseline.md` (or similar). -3. F39 can use this harness to verify the < 5 allocs/write target. - -**Resolves when:** baseline numbers are committed and the harness is reproducible. - -### F39 — Zero-copy codec pass (per R12) -**Severity:** P1 — M6 DoD bullet 3. -**Source:** `design/70-risks-and-open-questions.md` R12 + `design/60-roadmap.md:97-102`. -**Depends on:** F38 (bench harness must exist to verify). - -**Scope.** Convert the codec's encode path to `BytesMut::with_capacity(MAX_FRAME)` and the decode path to `bytes::Bytes` zero-copy slices where possible. Target < 5 allocations per write at steady state. Subscription stream should not allocate per-message (all per-frame buffers reused via a per-connection pool). - -**Definition of done:** -1. `cargo bench -p mxaccess-codec` reports < 5 allocs per write encode for the proven matrix. -2. Live `cargo run -p mxaccess --example subscribe -- --tag TestChildObject.TestInt` under churn (10+ Hz updates) shows zero per-message allocations in the steady-state region of the bench output. -3. No correctness regressions in the round-trip fixture suite. - -**Resolves when:** the bench numbers hit the targets and the workspace test suite stays green. ### F40 — Optional `metrics` feature: counters + histograms **Severity:** P2 — M6 DoD bullet 4 (optional `metrics` feature emitting counters / histograms). @@ -133,19 +89,6 @@ Print baseline numbers in a CSV/markdown table committed to `design/` so future **Resolves when:** baseline files exist and CI catches drift. -### F42 — `cargo doc` cleanup pass -**Severity:** P2 — M6 DoD bullet 5. -**Source:** `design/60-roadmap.md:99`. - -**Scope.** Run `cargo doc --workspace --no-deps` and fix every rustdoc warning (broken intra-doc links, missing top-level crate doc, missing examples on public items). Add `#![warn(missing_docs)]` lints to crate roots after the cleanup so future regressions are caught. - -**Definition of done:** -1. `cargo doc --workspace --no-deps -- -D warnings` passes clean. -2. Each crate has a top-level doc comment summarising its role. -3. Public API items have at least a one-line doc comment. - -**Resolves when:** the doc build is warning-clean and the lint enforces it going forward. - ### F43 — Release prep: `cargo publish --dry-run` all crates **Severity:** P1 — M6 DoD bullet 6. **Source:** `design/60-roadmap.md:100`. @@ -188,6 +131,18 @@ For `077` (Suspend on advised ScanState): document the trigger conditions for R5 ## Resolved +### F37 — ASB `subscribe_buffered` capability gate +**Resolved:** 2026-05-06 (commit `34045c2`). `AsbSession::subscribe_buffered` returns `Error::Unsupported { transport: TransportKind::Asb, operation: ... }` synchronously without touching the wire — ASB has no `SetBufferedUpdateInterval` analogue; the per-monitored-item `MinimalMonitoredItem::sample_interval` is the rate-limit knob instead. The error-construction logic is split into a free fn so the gate's exact shape is unit-testable without spinning up a live authenticator + transport. Workspace 758 → 759 tests; clippy clean. + +### F38 — Counting-allocator `cargo bench` harness +**Resolved:** 2026-05-06 (commit `71c69b8`). Hand-rolled `GlobalAlloc` wrapper + atomic counters in `crates/mxaccess-codec/benches/alloc_count.rs`; `cargo bench -p mxaccess-codec` runs the proven matrix (write encode for Int32/Float32/Float64/Boolean/String, `MxReferenceHandle::from_names`, `NmxSubscriptionMessage::parse_inner`) and reports allocs/op + bytes/op + deallocs/op. Baseline numbers committed to `design/M6-bench-baseline.md`. Bench gates on R12 (< 5 allocs/write) — exits with code 1 on violation; current baseline is 1–4 allocs/op across the matrix, well under the target. + +### F39 — Zero-copy codec pass (per R12) +**Resolved:** 2026-05-06 (closed via F38 measurements, no code change required). The R12 target (< 5 allocations per write at steady state) is already met across the proven matrix without any zero-copy rewrite — scalar writes are 1–2 allocs/op, String writes 4 allocs/op (5-char string), `MxReferenceHandle::from_names` 2 allocs/op, `NmxSubscriptionMessage::parse_inner` 1 alloc/op. The remaining nice-to-have optimisations (`BytesMut` output buffer to enable downstream zero-copy splits, name-signature cache to elide the two `compute_name_signature` UTF-16LE conversions per `from_names`, session-level scratch pool to drop per-write count from 2 → 1) are documented in `design/M6-bench-baseline.md` as post-V1 work — they don't gate M6 DoD because R12 is already satisfied. + +### F42 — `cargo doc` cleanup pass +**Resolved:** 2026-05-06 (commit `e79e289`). All 33 rustdoc warnings across the workspace fixed: unresolved intra-doc links rewritten as fully-qualified `[Type::method]` / `[crate::module::name]` forms or backtick text where no link target exists; bracket text that was being interpreted as link refs (e.g. `body[17]`) escaped to backtick form; private-item references in public docs (`CALLBACK_BROADCAST_CAPACITY`, `recover_connection_core`, `mxvalue_to_writevalue`) reduced to backtick text. `RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps` exits clean. Workspace 759 tests pass; clippy clean. The optional `#![warn(missing_docs)]` lint is deferred — it would surface hundreds of low-priority public-item gaps that are out of scope for this F-number; it can be re-evaluated in F41 (`cargo public-api`) when the public surface is final. + ### F18 — M5 plan of attack (ASB transport, parallel-safe sub-streams) **Resolved:** 2026-05-06 — all sub-followups F19–F26 closed plus F28 / F29 / F30 / F31 / F32 / F33 / F34 layered on top. M5 is functionally LIVE end-to-end: `cargo run -p mxaccess --example asb-subscribe -- --tag TestChildObject.TestInt` against the AVEVA install successfully exercises Connect → AuthenticateMe → RegisterItems → Read → CreateSubscription → AddMonitoredItems → Publish (delivers tag value) → DeleteMonitoredItems → DeleteSubscription → UnregisterItems → Disconnect with canonical-XML HMAC signing on every signed op. **Severity:** P0 — milestone driver, blocks ASB consumers + V1 release. **Source:** `design/dependencies.md:73-89` + `design/60-roadmap.md:84-91` + `design/70-risks-and-open-questions.md:5-25`.