14 KiB
Gap Analysis — Orchestrator Instructions
Instructions for an LLM to launch parallel subagents that analyze and maintain the gap inventory across all 19 categories.
Overview
The gaps/ directory tracks what has been ported from the Go NATS server to the .NET port. Each category has its own <category>.md file with:
- Go reference file paths
- .NET implementation file paths
- A Gap Inventory table (populated or empty)
- Instructions for how to analyze the gap
The orchestrator's job is to launch one subagent per category, collect results, and update stillmissing.md with fresh LOC numbers.
Mode Detection
Before launching subagents, determine the mode:
IF the Gap Inventory table in a category file has only the empty template row → INITIAL mode
IF the Gap Inventory table has populated rows → UPDATE mode
You can check all files at once:
for f in gaps/*.md; do
[ "$f" = "gaps/stillmissing.md" ] && continue
[ "$f" = "gaps/instructions.md" ] && continue
rows=$(grep -c '^|[^|]*|[^|]*|' "$f" 2>/dev/null)
name=$(basename "$f" .md)
if [ "$rows" -le 3 ]; then
echo "INITIAL: $name"
else
echo "UPDATE: $name"
fi
done
Category Registry
Each category file and its complexity tier (determines model selection and context budget):
| Category File | Tier | Model | Go Source LOC | Notes |
|---|---|---|---|---|
core-server.md |
LARGE | opus | 21,223 | client.go alone is ~6,700 lines |
protocol.md |
SMALL | sonnet | 1,829 | 3 files, well-scoped |
subscriptions.md |
SMALL | sonnet | 2,416 | 2 files, well-scoped |
auth-and-accounts.md |
LARGE | opus | 7,260 | accounts.go is ~4,100 lines |
configuration.md |
SMALL | sonnet | 1,871 | 3 files |
routes.md |
MEDIUM | sonnet | 3,314 | 1 file |
gateways.md |
MEDIUM | sonnet | 3,426 | 1 file |
leaf-nodes.md |
MEDIUM | sonnet | 3,470 | 1 file |
jetstream.md |
X-LARGE | opus | 55,228 | Must be split into sub-passes |
raft.md |
MEDIUM | opus | 5,037 | 1 file, complex consensus logic |
mqtt.md |
MEDIUM | opus | 5,882 | 1 file |
websocket.md |
SMALL | sonnet | 1,550 | 1 file, near-complete (99%) |
monitoring.md |
MEDIUM | sonnet | 4,396 | 2 files |
events.md |
MEDIUM | sonnet | 4,133 | 2 files |
tls-security.md |
MEDIUM | opus | 4,207 | Multiple files + subdirs |
internal-ds.md |
MEDIUM | sonnet | 4,020 | Already at 105% parity |
logging.md |
TRIVIAL | haiku | 936 | Likely all NOT_APPLICABLE |
utilities-and-other.md |
MEDIUM | sonnet | 3,282 | Mixed bag of small files |
misc-uncategorized.md |
SMALL | haiku | 660 | Remainder items |
Launching Subagents
Parallelism Strategy
Launch all subagents in a single message using multiple Task tool calls. All 19 categories are independent — they read different Go files and write to different output files.
Exception: JetStream (X-LARGE). JetStream has 55,228 Go source LOC across 15 files. A single subagent cannot read all files in one context window. Launch it as a foreground task and handle it specially (see JetStream section below).
Subagent Tool Configuration
For each category, use the Task tool with:
subagent_type: "general-purpose"
model: <from Category Registry table>
description: "Analyze <category> gaps"
Prompt Templates
INITIAL Mode Prompt
Use this prompt when the Gap Inventory table is empty:
You are analyzing the Go-to-.NET porting gap for the {CATEGORY_NAME} module of the NATS server.
## Your Task
Read the category file at `gaps/{CATEGORY_FILE}` — it contains:
- Detailed analysis instructions (Steps 1-5)
- Go reference file paths
- .NET implementation file paths
- Key porting notes specific to this category
Follow the instructions in that file exactly. Specifically:
1. Read each Go source file listed under "Go Reference Files (Source)"
2. For each file, extract all exported types, methods, and standalone functions
3. Read the .NET files listed under ".NET Implementation Files (Source)"
4. For each Go symbol, search for its .NET equivalent
5. Classify each item as PORTED, PARTIAL, MISSING, NOT_APPLICABLE, or DEFERRED
6. Write the results into the Gap Inventory table in `gaps/{CATEGORY_FILE}`
## Output Format
Edit `gaps/{CATEGORY_FILE}` to populate the Gap Inventory table. Each row must have:
- **Go Symbol**: The type or function name (e.g., `Server.Start`, `processMsg`, `RouteInfo`)
- **Go File:Line**: Path relative to repo root with line number (e.g., `golang/nats-server/server/route.go:142`)
- **Status**: One of PORTED, PARTIAL, MISSING, NOT_APPLICABLE, DEFERRED
- **NET Equivalent**: Path to .NET file:line if it exists (e.g., `src/NATS.Server/Routes/RouteManager.cs:55`)
- **Notes**: Brief explanation, especially for PARTIAL (what's missing) and NOT_APPLICABLE (why)
Group rows by Go source file. Use markdown sub-headers within the table comments if helpful.
## Important Rules
- Do NOT modify any source code (.go or .cs files) — this is a read-only analysis
- Do NOT modify `gaps/stillmissing.md` — the orchestrator handles LOC updates
- DO update the Change Log at the bottom of the category file
- Focus on **exported/public API surface** first, then important unexported helpers
- For large files (>2,000 lines), work through them methodically — top to bottom, section by section
- Skip trivial getters/setters unless they contain logic
UPDATE Mode Prompt
Use this prompt when the Gap Inventory table already has data:
You are updating the gap analysis for the {CATEGORY_NAME} module of the NATS server.
## Your Task
The file `gaps/{CATEGORY_FILE}` already has a populated Gap Inventory table from a previous analysis. Your job is to:
1. Read the current Gap Inventory in `gaps/{CATEGORY_FILE}`
2. For each item marked MISSING or PARTIAL:
- Search the .NET codebase to check if it has been ported since the last analysis
- If now ported, update the status to PORTED and fill in the .NET Equivalent path
- If partially ported, update notes with current state
3. Check for NEW Go symbols that were added since the last analysis:
- Read the Go source files listed in the category file
- Compare against the existing inventory
- Add rows for any new symbols not yet tracked
4. Check for NEW .NET files that may cover previously MISSING items:
- Glob for new .cs files in the .NET directories listed in the category file
- Cross-reference against MISSING items
5. Update the Change Log at the bottom
## Output Format
Edit `gaps/{CATEGORY_FILE}` in place:
- Update existing rows (change status, add .NET paths)
- Add new rows for newly discovered symbols
- Do NOT remove existing rows — even if the Go symbol was removed, mark it as NOT_APPLICABLE with a note
- Update the Change Log with today's date and a summary
## After Updating the Inventory
Run the LOC re-count commands from the "Keeping This File Updated" section of the category file and report the new numbers in your output so the orchestrator can update stillmissing.md.
## Important Rules
- Do NOT modify any source code — read-only analysis
- Do NOT modify `gaps/stillmissing.md` — report numbers, the orchestrator updates it
- Preserve all existing inventory rows
JetStream Special Handling
JetStream is too large for a single subagent pass. Split it into 5 sub-passes, launched sequentially or with careful scoping:
| Sub-pass | Go Files | Focus |
|---|---|---|
| JS-1: Core | jetstream.go, jetstream_api.go, jetstream_events.go, jetstream_errors.go, jetstream_versioning.go, jetstream_batching.go |
Orchestration, API handlers |
| JS-2: Stream | stream.go, store.go |
Stream lifecycle, retention policies |
| JS-3: Consumer | consumer.go |
Consumer state machine, delivery modes |
| JS-4: Storage | filestore.go, memstore.go, dirstore.go, disk_avail.go |
Persistent storage, compression, encryption |
| JS-5: Cluster | jetstream_cluster.go |
Clustered JetStream coordination |
Launch JS-1 through JS-5 as separate subagents (can run in parallel). Each writes to gaps/jetstream.md — but since they write different sections of the Gap Inventory table, use section headers within the table to avoid conflicts:
<!-- === JS-1: Core === -->
| JetStream.enableJetStream | jetstream.go:245 | PORTED | ... | ... |
...
<!-- === JS-2: Stream === -->
| stream.processInboundJetStreamMsg | stream.go:112 | MISSING | | ... |
...
Alternatively, launch them sequentially (JS-1 first, then resume the agent for JS-2, etc.) to avoid write conflicts.
After All Subagents Complete
Step 1: Collect LOC Numbers
Each subagent in UPDATE mode should report its re-counted LOC. If running INITIAL mode, the orchestrator runs LOC counts itself:
cd /Users/dohertj2/Desktop/natsdotnet
echo "=== .NET Source LOC by Category ==="
echo "core-server|$(find src/NATS.Server/ -maxdepth 1 -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "protocol|$(find src/NATS.Server/Protocol/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "subscriptions|$(find src/NATS.Server/Subscriptions/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "auth-and-accounts|$(find src/NATS.Server/Auth/ src/NATS.Server/Imports/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "configuration|$(find src/NATS.Server/Configuration/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "routes|$(find src/NATS.Server/Routes/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "gateways|$(find src/NATS.Server/Gateways/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "leaf-nodes|$(find src/NATS.Server/LeafNodes/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "jetstream|$(find src/NATS.Server/JetStream/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "raft|$(find src/NATS.Server/Raft/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "mqtt|$(find src/NATS.Server/Mqtt/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "websocket|$(find src/NATS.Server/WebSocket/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "monitoring|$(find src/NATS.Server/Monitoring/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "events|$(find src/NATS.Server/Events/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "tls-security|$(find src/NATS.Server/Tls/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "internal-ds|$(find src/NATS.Server/Internal/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo "logging|0"
echo "utilities-and-other|$(find src/NATS.Server/IO/ src/NATS.Server/Server/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l)"
echo ""
echo "=== .NET Source TOTAL ==="
find src/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l
echo ""
echo "=== .NET Test TOTAL ==="
find tests/ -name '*.cs' -type f -exec cat {} + 2>/dev/null | wc -l
echo ""
echo "=== .NET File Counts ==="
echo "source|$(find src/ -name '*.cs' -type f | wc -l)"
echo "test|$(find tests/ -name '*.cs' -type f | wc -l)"
Step 2: Update stillmissing.md
Compare the new LOC numbers against the values in gaps/stillmissing.md. For each category where the .NET LOC changed:
- Edit the row in the "Source Code by Functional Area" table
- Recalculate the
.NET/Gopercentage:round(.NET LOC / Go LOC * 100) - Update the
.NET Filescount if new files were added - Update the Summary table totals
- Update the "Generated" date in the header
Do NOT change Go LOC numbers unless the Go reference has been updated (rare).
Step 3: Generate Summary Report
After all subagents complete, produce a summary for the user:
## Gap Analysis Summary — {DATE}
### Status Counts (across all categories)
- PORTED: {n}
- PARTIAL: {n}
- MISSING: {n}
- NOT_APPLICABLE: {n}
- DEFERRED: {n}
### Categories with Most MISSING Items
1. {category}: {n} missing
2. {category}: {n} missing
3. {category}: {n} missing
### LOC Changes Since Last Run
| Category | Previous .NET LOC | Current .NET LOC | Delta |
|----------|------------------:|-----------------:|------:|
| ... | ... | ... | ... |
### Categories Needing Attention
- {category}: {reason}
Count statuses by grepping the inventory tables:
for f in gaps/*.md; do
[ "$f" = "gaps/stillmissing.md" ] && continue
[ "$f" = "gaps/instructions.md" ] && continue
name=$(basename "$f" .md)
ported=$(grep -c '| PORTED |' "$f" 2>/dev/null || echo 0)
partial=$(grep -c '| PARTIAL |' "$f" 2>/dev/null || echo 0)
missing=$(grep -c '| MISSING |' "$f" 2>/dev/null || echo 0)
na=$(grep -c '| NOT_APPLICABLE |' "$f" 2>/dev/null || echo 0)
deferred=$(grep -c '| DEFERRED |' "$f" 2>/dev/null || echo 0)
echo "$name|$ported|$partial|$missing|$na|$deferred"
done
Quick-Start: Full Initial Run
Copy-paste orchestration sequence:
- Check mode — run the mode detection script above
- Launch all subagents — use the Task tool 19 times in a single message (see parallelism strategy)
- Handle JetStream — if INITIAL mode, launch 5 JS sub-passes
- Wait for completion — all subagents run in background; you're notified on completion
- Collect LOC — run the LOC counting script
- Update stillmissing.md — edit the table with new numbers
- Generate summary — run the status counting script and format the report
Quick-Start: Incremental Update
After porting work has been done:
- Identify changed categories — check git diff for which
src/directories were modified:git diff --name-only HEAD~10 -- src/ | sed 's|src/NATS.Server/||' | cut -d/ -f1 | sort -u - Launch subagents only for changed categories — no need to re-analyze unchanged modules
- Collect LOC and update stillmissing.md — same as full run but only for changed categories
Error Handling
- Subagent hits context limit: This typically happens with LARGE/X-LARGE categories. If a subagent reports it couldn't finish, resume it with the
resumeparameter and instruct it to continue from where it left off. - Subagent finds no .NET files: The category may not be ported yet. Mark all items as MISSING and note the empty state.
- Conflicting writes to jetstream.md: If running JS sub-passes in parallel, use the section-header approach described above. If conflicts occur, run sub-passes sequentially instead.
- Go files changed upstream: If the Go reference was updated (
golang/nats-server/), run a full INITIAL analysis to catch new symbols. Check with:git log --oneline -5 -- golang/