Files
mxaccess/design/dependencies.md
Joseph Doherty 16f2c148e5 design: parallelism map + /loop driver prompt + followups triage
- design/dependencies.md: per-milestone parallelism map for M2–M6 with
  per-phase agent budgets (peak 4 in parallel for M5 framing wave;
  7-agent maximum if M2 wave 1 + M5 framing run concurrently).
- design/prompt.md: self-contained /loop driver. Step 0 triages
  design/followups.md (auto-resolves items whose preconditions are met,
  shelves the rest). Step 3 spawns parallel general-purpose agents per
  design/dependencies.md when the active wave has multiple lanes.
  Sequential lanes (M4 Session core, M5 client integration) run directly.
  Local-commit-only by default; explicit stop conditions; Q7 hasDetailStatus
  audit reminder for any new conditional-read codec port.
- design/README.md: index updated to reference prompt.md, followups.md,
  dependencies.md, and review.md.

design/followups.md is intentionally not pre-created — prompt.md Step 0
bootstraps it on first /loop run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 06:34:30 -04:00

170 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dependencies and parallelism map
Where the M2M6 work can be run in parallel, where it can't, and the agent
budget per phase. Sits alongside [`60-roadmap.md`](60-roadmap.md) — the
roadmap describes what each milestone delivers and its DoD; this file
describes the dependency graph **inside and across** milestones so multiple
agents (or developers) can be scheduled without stepping on each other.
## Cross-milestone parallelism
Already encoded in the roadmap's "Sequencing dependencies" table. The headline:
```
M0 ─► M1 ─► M2 ─► M3 ─► M4 ─┐
│ ├─► M6 ─► release
└─────────► M5 ─────┘
```
**M5 (entire ASB path) runs in parallel with M3+M4 (entire NMX path).** This
is only possible because the cluster-4 sequencing fix moved the `Transport`
trait + `Session` shape to M0 — they are stable enough at M0 that M5 can
build against the trait without waiting for M4 to land the NMX impl. ASB has
no transitive dependency on DCE/RPC, NTLM, OBJREF, or OXID.
The other dependency edges are tight: M3 cannot run in parallel with M2 (it
needs the live RPC transport to drive `register_engine_2`); M4 cannot run in
parallel with M3 (the async session wraps the raw NMX client built in M3).
## Within-milestone parallelism
### M2 — DCE/RPC + NTLM + OBJREF + OXID + callback exporter
| Wave | Parallelizable streams | Why they're independent |
|---|---|---|
| **1** | **(a) NTLMv2 client context · (b) DCE/RPC PDU codec · (c) OBJREF parser** | All pure-codec/crypto, no I/O, no shared state. Each maps cleanly to one Rust module under `mxaccess-rpc`. |
| 2 | (d) OXID resolution · (e) `IRemUnknown::RemQueryInterface` | Both depend on (b) but not on each other. |
| 3 | (f) Callback exporter (the `mxaccess-callback` crate — `INmxSvcCallback` server, `IRemUnknown` server, OBJREF export) | Depends on (a), (b), (e). Single crate, single agent. |
**Peak agents in parallel: 3** (wave 1). Each agent owns one `.cs` source
family in `src/MxNativeClient/` and emits one Rust module.
### M3 — NMX session + Galaxy resolver
| Stream | Owns | Depends on |
|---|---|---|
| **A** | `mxaccess-galaxy`: SQL resolver (`tag_name`-form input only — `wwtools/grdb/`), user resolver, `dbo.schema_version` startup probe | M0 + M1 (`MxReferenceHandle` for the output type) |
| **B** | `mxaccess-nmx`: `NmxClient` with `register_engine_2`, `transfer_data`, `add_subscriber_engine`, `set_heartbeat_send_interval`, `unregister_engine`, `get_partner_version`. Builds `MxReferenceHandle` from resolver output + CRC-16/IBM. | M2 (DCE/RPC + callback exporter) |
A and B are fully independent — different crates, different `.cs` reference
sources, different external dependencies. **2 agents in parallel.** B can be
sub-paralleled per opnum (4 small tasks for the four primary methods) if a
third agent is available.
### M4 — Async Tokio façade (NMX path)
This is the milestone where parallelism helps least. The `Session`
orchestration layer is genuinely sequential — the recovery state machine,
the connection task that owns the TCP stream + callback channel, and the
correlation-ID bookkeeping are one cross-cutting design that's hard to chunk
across agents without integration pain.
| Wave | Parallelizable | Notes |
|---|---|---|
| 1 | (a) `Session` core + long-lived connection task · (b) `RecoveryPolicy` + `RecoveryEvent` types | (b) is small but design-pivotal — agree the event shape before consumers depend on it. |
| 2 | (c) write family: `write`, `write_with_completion`, `write_with_timestamp`, `write_secured`, `write_secured_at` · (d) subscribe family: `read`, `subscribe`, `subscribe_many`, `subscribe_buffered` | After (a) lands. (c) and (d) share the connection task but operate on disjoint state. |
| 3 | All 7 example programs (`connect-write-read.rs`, `subscribe.rs`, `subscribe-buffered.rs`, `recovery.rs`, `multi-tag.rs`, `secured-write.rs`, `asb-subscribe.rs`) | Pure consumer code, no API impact. Can split to one agent per example. |
**Peak agents in parallel: 2** in wave 2 (write-family vs subscribe-family).
Don't try to split tighter — the connection task has too much shared mutable
state (subscription registry, in-flight correlation table, recovery flag).
### M5 — ASB transport
The heaviest milestone in raw LoC after the `wwtools/mxaccesscli/`
verification. The R1 estimate (`70-risks-and-open-questions.md`) puts it at
~3000 LoC for the framing + encoder layers alone. It splits cleanly along
spec boundaries:
| Stream | Owns |
|---|---|
| **A** | `[MS-NMF]` net.tcp framing — record types (preamble, preamble-ack, sized-envelope, end, fault) + reliable-session ack handling on the underlying TCP channel |
| **B** | `[MC-NBFX]` binary-XML node codec — read/write tokenised XML (start-element, end-element, attribute, text, etc.) |
| **C** | `[MC-NBFS]` static dictionary table — the SOAP/WS-Addressing/`IASBIDataV2` action strings the encoder references by ID instead of inlining |
| **D** | Application auth: DH key exchange (constant-time `crypto-bigint` rather than the .NET `BigInteger.ModPow` defect) + HMAC integrity + AES-128 + DPAPI shared-secret read on Windows |
| **E** | `mxaccess-asb` client: `Connect`, `RegisterItems`, `Read`, `Write`, `CreateSubscription`, `AddMonitoredItems`, `Publish`, `Disconnect`. Depends on A+B+C+D. |
**Peak agents in parallel: 4** in the framing/encoding wave (A+B+C+D), then
E is sequential (or 2-way: read/write paths vs subscription paths).
### M6 — Compat shim + production hardening
Fully parallel — the four streams are different crates or different
feature gates, no inter-stream design coupling.
| Stream | Owns |
|---|---|
| **A** | `mxaccess-compat`: `LMXProxyServer`-shaped methods layered on top of `Session`. Streams + async fns; the `mxaccess-compat-com` (post-V1) registers `windows-rs`-generated COM classes on top. |
| **B** | Performance pass: `bytes::Bytes` zero-copy on receive paths, `BytesMut` pre-allocation per session, codec allocation count benchmarked, hits R12's `< 5 allocations per write at steady state` target. |
| **C** | `metrics` feature: counters + histograms via the `metrics` crate. Optional, not on the default-feature path. |
| **D** | Docs + release: `cargo doc`, `cargo public-api` baseline, README polish, `cargo publish` per crate in topological order. |
**Peak agents in parallel: 4.** Each owns a different module or feature, no
shared mutable state.
## Practical agent budget
| Phase | Peak parallel agents | Sequential bottleneck |
|---|---|---|
| M2 | 3 (wave 1) | callback exporter (wave 3) |
| M3 | 2 | live-probe DoD (single AVEVA install) |
| M4 | 2 | `Session` core + connection task |
| M5 | 4 (framing wave) | client (E) |
| M6 | 4 | none — release sequencing only |
If running as agents-in-parallel-per-wave the way M1 ran, peak utilization
is **4 agents** (M5 framing wave). The honest sequential bottleneck is M4's
`Session` orchestration — that's the one milestone where parallelism doesn't
help much because the recovery state machine is one tightly-coupled design.
## Wall-clock estimate
Strictly sequential (one developer, one stream): roughly the M2M6 LoC
volume divided by sustained Rust output. Realistic estimate ~1216 weeks
for V1 from M2 start.
Aggressive parallelism (M5 in parallel with M3+M4 + within-milestone agent
fan-out): roughly **60% of the sequential wall-clock**, ~710 weeks. Past
that point, coordination overhead and integration debugging eat the gains.
The biggest single win is the M5-parallel-with-M3+M4 lane: ~34 weeks saved
on its own. Within-milestone parallelism saves a further ~12 weeks per
milestone but flattens out fast — splitting M4 into 4 streams is not 4×
faster than 2 streams.
## Constraints that block further parallelism
These are **not** within-our-control bottlenecks; listing them so they don't
get treated as parallelization opportunities:
1. **Live-probe DoDs need a single live AVEVA install.** Two agents can't
both probe `register_engine_2` against the same `NmxSvc.exe` at the same
time — the second one races against the first's RPC channel.
Live-probing is sequential per shared resource.
2. **Captured-fixture round-trip tests are CPU-bound but trivially small.**
Not worth parallelizing the runner.
3. **Cross-cutting design decisions** (error taxonomy, recovery semantics,
`tracing` field naming) need to land before consumer code can be
written. These are "wave 0" of each milestone — single-agent, fast.
4. **`cargo publish` ordering** is a true topological sort (codec before
transport before session); cannot be parallelized.
## Recommended sequencing
If picking which lane to push next given the M0+M1 state today:
1. **M2 wave 1 (3 agents)** — NTLM, DCE/RPC PDU codec, OBJREF parser. Highest
parallelism return, foundational for everything else.
2. **M5 framing wave (4 agents) in parallel with M2 wave 1** — only if you
have agent budget. Both ship to `mxaccess-asb-nettcp` and the M2
work; they don't overlap. **This is the maximum-parallelism configuration —
7 agents working concurrently.**
3. **M3 stream A (Galaxy resolver) in parallel with M2 wave 3** — Galaxy
doesn't need the RPC transport; it can develop while the callback
exporter is being built.
4. **M4 wave 1 (Session core + RecoveryPolicy)** — sequential after M3
stream B lands.
5. **M6 (4 agents)** — once both M4 and M5 land.
Beyond step 5, the work is release-engineering, not feature work.