Files
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

12 KiB
Raw Permalink Blame History

/loop driver — autonomous M2M6 implementation

You are inside a /loop iteration for the mxaccess Rust port at c:\Users\dohertj2\Desktop\mxaccess. Your goal each iteration: advance the project by one cohesive unit of work, verify it doesn't regress, commit it locally, and either schedule the next iteration or stop and surface.

This file is re-fed to you on every iteration with no carry-over state. Read it top-to-bottom each time. Discover everything else from the project itself.


Iteration protocol

Step 0 — Triage design/followups.md

Read design/followups.md. If it does not exist, create it with this skeleton:

# Followups

Open work items deferred during /loop iterations. Triaged at the top of
every iteration. New items are appended under `## Open`; resolved items
move to `## Resolved` with a date + commit hash.

## Open

(none yet)

## Resolved

(none yet)

Then for each item under ## Open:

  1. Read the Resolves when: clause.
  2. If its preconditions are met now (the gating commit landed, the ambiguity it flagged is now resolved, etc.) → solve it as part of this iteration's work, then move it to ## Resolved with today's date and the resolving commit hash (the commit you make in Step 5 below).
  3. If preconditions are not met → leave it under ## Open and move on.

If ## Open exceeds 10 items, STOP and surface to the user — that's a drift signal that needs human triage, not more iterations.

Step 1 — Discover state

Run in parallel (single assistant message, multiple tool calls):

  • git log --oneline -20
  • cd rust && cargo test --workspace 2>&1 | grep "test result:" | grep -v "0 passed" | tail -5 — must show all-pass results.
  • Read design/60-roadmap.md, design/dependencies.md, design/review.md.

If cargo test is not green at the start of the iteration:

  1. Diagnose with cargo build and the failing test name.
  2. Apply one targeted fix.
  3. If the fix doesn't recover green: git reset --hard HEAD, log a followup describing the failure mode, and STOP.

Never proceed past Step 1 with a red baseline.

Step 2 — Identify the current phase and unblocked lanes

From the git log + recent commits, determine which milestone is in flight:

  • Most recent [M0] / [M1] / [M2] / ... commits → that's the active phase.
  • If the active phase's DoD (per design/60-roadmap.md) is fully met, the next iteration's work is the next milestone. Advance the phase marker mentally.

Then consult design/dependencies.md for the active phase's parallelism map. Identify which lanes are unblocked right now (their dependencies have landed in earlier commits).

The summary table for fast lookup:

M2 wave 1: 3 agents — NTLMv2 client / DCE/RPC PDU codec / OBJREF parser
M2 wave 2: 2 agents — OXID resolution / IRemUnknown::RemQueryInterface
M2 wave 3: 1 agent  — mxaccess-callback (the INmxSvcCallback exporter)
M3:        2 agents — mxaccess-galaxy / mxaccess-nmx
M4 wave 1: 1 agent  — Session core + RecoveryPolicy types  (sequential)
M4 wave 2: 2 agents — write family / subscribe family
M4 wave 3: 7 agents — examples (one each)
M5:        4 agents — MS-NMF framing / MC-NBFX codec / MC-NBFS dictionary / DH+HMAC+AES
M5 client: 1 agent  — mxaccess-asb operations  (sequential after framing)
M6:        4 agents — mxaccess-compat / perf / metrics / docs

Pick the smallest unit that:

  • Is currently unblocked (dependencies landed).
  • Is not already covered by an open followup that's deferred.
  • Can be completed in one iteration's work (one commit's worth).

Step 3 — Execute

If the active wave has multiple parallel streams (any row above with N agents where N > 1), spawn that many general-purpose agents in one single message containing N parallel Agent tool calls. Each agent owns one .cs source file (or one logical unit) and emits one Rust module.

Each agent's prompt MUST include:

  • Project context (one paragraph: this is the mxaccess Rust port, src/ is the executable spec, CLAUDE.md forbids fabrication).
  • The exact .cs source path to port.
  • The exact Rust output module path.
  • Reference to existing M1 modules as the pattern to follow (reference_handle.rs, envelope.rs, status.rs).
  • Test requirements: round-trip, boundary checks, citation-bearing parity vectors against tools/Compute-Crc.ps1 style helpers where applicable.
  • Hard rule: do NOT edit lib.rs. The driver wires up modules after agents finish.
  • Audit reminder: any conditional read pattern (hasDetailStatus-style) must mirror the .NET reference's unconditional/conditional split exactly (design/70-risks-and-open-questions.md Q7 — the M1 wave-1 audit defect).

If the work is sequential (M4 Session core, M5 client integration after framing lands, any wave with 1 agent), do it directly. Read the .cs source, port it inline, write tests inline. Do not spawn an agent for sequential single-stream work.

After parallel agents return: wire up lib.rs (mod declarations + re-exports) and remove any stub types they replaced.

Step 4 — Verify

Run all four DoD gates:

  • cargo build --workspace --all-targets
  • cargo test --workspace --no-fail-fast
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo fmt --all -- --check

For codec changes also verify the .NET parity test still passes:

  • cargo test -p mxaccess-codec --test dotnet_codec_parity

If any gate fails:

  1. Try one targeted fix.
  2. If still failing → git reset --hard HEAD. Append a followup. STOP.

Step 5 — Commit (local only)

  • git add -A.
  • Commit message format:
[M<n>] <crate>: <one-line summary, ≤ 70 chars>

<body bullets, what changed and why, citing src/...:LINE for protocol claims>
- Test count delta: NNN → MMM (+K)
- Open followups touched: F<N>, F<N> (or "none")

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
  • Do not push. The user pushes manually unless they've explicitly enabled auto-push for the loop. If auto-push has been enabled (you'll know because they invoked /loop with that flag or said so in this iteration's pre-amble), then git push after the commit.

Step 6 — Log new followups

For each item this iteration discovered but did not solve, append to design/followups.md under ## Open using this schema:

### F<N> — <one-line title>
**Severity:** P0 | P1 | P2 | P3
**Source:** commit <hash>
**Why deferred:** <reason — e.g. "needs M3 NMX client to verify wire round-trip", "ambiguous protocol question, no evidence in src/ or captures/">
**Resolves when:** <preconditions — what must land or change for this to be actionable>
**Notes:** <optional cross-links to design/*.md sections>

<N> is the next free integer (highest existing F-number + 1, or 1 on first followup).

Common follow-up sources:

  • An agent reported a deviation from the .NET reference that requires a separate design-decision turn.
  • A risk register item (R1R16 / Q1Q7) was hit but did not block this iteration's work.
  • A test fixture is missing and would require a new live capture.
  • A dep-version bump or feature-gate decision arose that needs a workspace-level agreement.

Step 7 — Decide next

Condition Action
Milestone DoD fully satisfied (per 60-roadmap.md) Make a final [Mn-done] commit summarising the milestone, then ScheduleWakeup for next milestone start.
Hit ambiguous protocol question (no evidence in src/ / docs/ / captures/) Log followup, STOP, surface to user.
Hit P0/P1 blocker tracked in 70-risks-and-open-questions.md Log followup, STOP, surface.
3 consecutive iterations with zero net progress (no new commit, no resolved followup) STOP, surface to user.
## Open followups list > 10 items STOP, ask user to triage.
M6 DoD fully satisfied Project complete. STOP. Do not schedule.
Otherwise ScheduleWakeup with delaySeconds in 60270 (cache stays warm).

When you call ScheduleWakeup, pass the literal sentinel <<autonomous-loop-dynamic>> as prompt so the runtime re-resolves these instructions. Use a one-sentence reason describing what the next iteration will pick up.


Hard rules (do not negotiate)

  • No fabricated protocol behaviour. Every wire-byte, IID, opnum, HRESULT, byte-offset, or layout claim must cite src/MxNativeCodec/*.cs:LINE, src/MxNativeClient/*.cs:LINE, src/MxAsbClient/*.cs:LINE, docs/*.md:LINE, analysis/frida/*.tsv, or captures/0NN-frida-*. If you can't cite, you can't claim. Log a followup instead.
  • No --force, --no-verify, --no-gpg-sign on git commands.
  • No amending pushed commits. Always create new commits.
  • No deleting or rewriting files in captures/, analysis/frida/, analysis/proxy/, analysis/decompiled-*/, or analysis/ghidra/exports/. These are evidence per CLAUDE.md.
  • No editing lib.rs from an agent. The driver wires up modules.
  • No skipping verification. All four cargo gates green or revert.
  • No pushing without authorization. Commit locally only by default.
  • Preserve unknown bytes. Match the .NET reference round-trip for any field whose semantics are not yet decoded. Use [u8; N] preservation fields and document with a :LINE citation.
  • Tests over assertions. Do not add assert!(true) or assert!(<const expr>) at runtime; use const _: () = assert!(...) for compile-time checks.
  • Conditional reads must match the .NET reference exactly — see design/70-risks-and-open-questions.md Q7 (hasDetailStatus audit). Any field the .NET reads unconditionally must be read unconditionally in Rust.

Self-check before scheduling next iteration

Before calling ScheduleWakeup, verify each:

  • cargo build --workspace --all-targets exited 0.
  • cargo test --workspace exited 0 with all-pass results.
  • cargo clippy --workspace --all-targets -- -D warnings exited 0.
  • cargo fmt --all -- --check exited 0.
  • One commit landed this iteration (verify with git log -1 --oneline).
  • If any followup was deferred this iteration, design/followups.md has the new entry.
  • delaySeconds is in [60, 270] for cache-warm continuation, or in [1200, 3600] if waiting on a genuinely slow external process.

If any item fails, do not schedule next iteration. Surface to the user.


Useful commands reference

# State discovery
cd c:\Users\dohertj2\Desktop\mxaccess
git log --oneline -20
git status --short

# Rust gates (run from rust/)
cd rust
cargo build --workspace --all-targets
cargo test --workspace --no-fail-fast
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --all -- --check
cargo test -p mxaccess-codec --test dotnet_codec_parity

# Live-probe gating (M3+ only)
. ..\tools\Setup-LiveProbeEnv.ps1
cargo test -p mxaccess --features live -- --ignored

# .NET parity helpers
dotnet build src\MxNativeCodec\MxNativeCodec.csproj
pwsh -NoProfile -File tools\Compute-Crc.ps1

Why this design

  • Step 0 first keeps followups.md from rotting. Items that became solvable get cleaned up immediately.
  • Step 1's red-baseline check prevents iterations from compounding bugs.
  • Step 3's parallel-agent fan-out is the throughput lever — M2 wave 1 and M5 framing both run 34 agents concurrently, cutting wall-clock.
  • Step 5's local-commit-only default is reversibility. A bad iteration can be git reset --hard HEAD~1 without affecting any remote.
  • Step 7's stop conditions are explicit and disjoint. There's no "if it feels right, stop" phrasing — every stop condition has a measurable trigger.
  • Hard rules are lifted from CLAUDE.md so the loop cannot drift even if a single iteration loses context.