- 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>
12 KiB
/loop driver — autonomous M2–M6 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:
- Read the
Resolves when:clause. - 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
## Resolvedwith today's date and the resolving commit hash (the commit you make in Step 5 below). - If preconditions are not met → leave it under
## Openand 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 -20cd 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:
- Diagnose with
cargo buildand the failing test name. - Apply one targeted fix.
- 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
.cssource 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.ps1style 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.mdQ7 — 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-targetscargo test --workspace --no-fail-fastcargo clippy --workspace --all-targets -- -D warningscargo 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:
- Try one targeted fix.
- 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
/loopwith that flag or said so in this iteration's pre-amble), thengit pushafter 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 (
R1–R16/Q1–Q7) 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 60–270 (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, orcaptures/0NN-frida-*. If you can't cite, you can't claim. Log a followup instead. - No
--force,--no-verify,--no-gpg-signon git commands. - No amending pushed commits. Always create new commits.
- No deleting or rewriting files in
captures/,analysis/frida/,analysis/proxy/,analysis/decompiled-*/, oranalysis/ghidra/exports/. These are evidence per CLAUDE.md. - No editing
lib.rsfrom 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:LINEcitation. - Tests over assertions. Do not add
assert!(true)orassert!(<const expr>)at runtime; useconst _: () = assert!(...)for compile-time checks. - Conditional reads must match the .NET reference exactly — see
design/70-risks-and-open-questions.mdQ7 (hasDetailStatusaudit). 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-targetsexited 0.cargo test --workspaceexited 0 with all-pass results.cargo clippy --workspace --all-targets -- -D warningsexited 0.cargo fmt --all -- --checkexited 0.- One commit landed this iteration (verify with
git log -1 --oneline). - If any followup was deferred this iteration,
design/followups.mdhas the new entry. delaySecondsis 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.mdfrom 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 1andM5 framingboth run 3–4 agents concurrently, cutting wall-clock. - Step 5's local-commit-only default is reversibility. A bad iteration
can be
git reset --hard HEAD~1without 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.mdso the loop cannot drift even if a single iteration loses context.