# Batch 39 Consumer Dispatch Implementation Plan > **For Codex:** REQUIRED SUB-SKILL: Use `executeplan` to implement this plan task-by-task. **Goal:** Port and verify Batch 39 (`Consumer Dispatch`) from `server/consumer.go` so all 93 mapped features and 53 mapped tests are either genuinely implemented/verified or explicitly deferred with concrete blocker reasons. **Architecture:** Implement Batch 39 in five feature groups (`18/18/19/19/19`) with dispatch-focused `NatsConsumer` partial decomposition. After each feature group, execute mapped test waves and enforce strict evidence gates (stub scan, build gate, targeted tests, checkpoint) before any status promotion. **Tech Stack:** .NET 10, C# latest, xUnit 3, Shouldly, NSubstitute, PortTracker CLI, SQLite (`porting.db`) **Design doc:** `docs/plans/2026-02-27-batch-39-consumer-dispatch-design.md` --- ## Batch 39 Scope - Batch ID: `39` - Name: `Consumer Dispatch` - Dependency: `38` - Go source: `golang/nats-server/server/consumer.go` - Features: `93` - Tests: `53` If `dotnet` is not on `PATH`, use: ```bash DOTNET=/usr/local/share/dotnet/dotnet ``` Primary production files (expected): - Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Waiting.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Pull.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Acks.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Delivery.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Redelivery.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.ReplyParsing.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Shutdown.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsStream.Consumers.cs` - Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/StreamTypes.cs` Primary test files (expected): - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/NatsConsumerTests.cs` - Modify/Create: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/NatsConsumerDispatchTests.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/NatsConsumerTests.Impltests.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamEngineTests.Impltests.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests1.Impltests.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JwtProcessorTests.Impltests.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.Impltests.cs` - Create: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamClusterTests1.Impltests.cs` --- ## MANDATORY VERIFICATION PROTOCOL > **NON-NEGOTIABLE:** Every Batch 39 feature and test must pass this protocol. No shortcuts. ### 1. Dependency Preflight and Baseline Run before touching statuses: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- batch show 38 --db porting.db $DOTNET run --project tools/NatsNet.PortTracker -- batch show 39 --db porting.db $DOTNET run --project tools/NatsNet.PortTracker -- batch ready --db porting.db ``` Start Batch 39 only when ready: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- batch start 39 --db porting.db ``` Capture baseline: ```bash $DOTNET build dotnet/ $DOTNET test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ ``` ### 2. What Counts as a Real Port A **feature** is real only if all are true: 1. Mapped method/type exists and contains behavioral logic (not placeholder control flow). 2. Code path is exercised by at least one behavioral test. 3. Stub scan, build gate, and targeted tests are green. 4. Status promotion has traceable evidence. A **test** is real only if all are true: 1. Has Arrange/Act/Assert. 2. Calls production code from `ZB.MOM.NatsNet.Server.*`. 3. Uses meaningful Shouldly assertions on Act results/effects. 4. Contains no stub/template patterns. ### 3. Per-Feature Verification Loop (REQUIRED per feature ID) 1. Inspect mapped feature and Go source intent: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- feature show --db porting.db ``` 2. Claim the feature: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- feature update --status stub --db porting.db ``` 3. Add/adjust at least one behavioral test for the feature. 4. Implement minimal correct logic. 5. Run **Stub Detection Check**. 6. Run **Build Gate**. 7. Run relevant **Test Gate** filters. 8. Promote proven feature to `complete` (or `verified` only after checkpoint evidence). ### 4. Per-Test Verification Loop (REQUIRED per test ID) 1. Inspect mapped test and Go source: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- test show --db porting.db ``` 2. Claim the test: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- test update --status stub --db porting.db ``` 3. Port complete behavior. 4. Run single test and verify discovery: ```bash $DOTNET test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \ --filter "FullyQualifiedName~." --verbosity normal ``` 5. Confirm `Passed: 1, Failed: 0` (never `Passed: 0`). 6. Run class-level filter. 7. Run **Stub Detection Check** + **Build Gate**. 8. Promote proven test to `complete` (or `verified` only after checkpoint evidence). ### 5. Stub Detection Check (REQUIRED after each feature/test loop) ```bash changed_files=$(git diff --name-only -- dotnet/src/ZB.MOM.NatsNet.Server dotnet/tests/ZB.MOM.NatsNet.Server.Tests | rg "\\.cs$" || true) if [ -n "$changed_files" ]; then echo "$changed_files" | xargs rg -n "(NotImplementedException|// TODO|// PLACEHOLDER|Assert\\.True\\(true\\)|Assert\\.Pass\\(\\)|var goFile = \"server/|\\.ShouldContain\\(\"Should\"\\)|GetRequiredApiLevel\\(new Dictionary\\)\\.ShouldBe\\(string\\.Empty\\)|=>\\s*default;|return\\s+default;|return\\s+null;\\s*$|throw new Exception\\(\"TODO\"\\))" fi ``` Any match blocks status promotion until fixed or explicitly deferred. ### 6. Build Gate (REQUIRED) ```bash $DOTNET build dotnet/ ``` Run after every feature loop, every test loop, before any `batch-update`, and at each task checkpoint. ### 7. Test Gate (REQUIRED) Run the smallest relevant set after each change; run all of the following at checkpoints: ```bash $DOTNET test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --filter "FullyQualifiedName~JetStream.NatsConsumerTests|FullyQualifiedName~JetStream.NatsConsumerDispatchTests" $DOTNET test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --filter "FullyQualifiedName~ImplBacklog.NatsConsumerTests|FullyQualifiedName~ImplBacklog.JetStreamEngineTests" $DOTNET test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --filter "FullyQualifiedName~ImplBacklog.JetStreamClusterTests1|FullyQualifiedName~ImplBacklog.ConcurrencyTests1|FullyQualifiedName~ImplBacklog.JwtProcessorTests|FullyQualifiedName~ImplBacklog.RouteHandlerTests" ``` Checkpoint/full gate: ```bash $DOTNET test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ ``` ### 8. Status Update Protocol (HARD LIMIT: 15 IDs per batch-update) - Never send more than `15` IDs per `feature batch-update` or `test batch-update` call. - Never mark `verified` without checkpoint evidence. - Never update IDs outside the active task scope. - Keep blocked items `deferred` with specific reason text. Use: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- \ feature batch-update --ids "" --set-status --db porting.db --execute $DOTNET run --project tools/NatsNet.PortTracker -- \ test batch-update --ids "" --set-status --db porting.db --execute ``` ### 9. Checkpoint Protocol Between Tasks (REQUIRED) Before moving to the next task: 1. Run **Stub Detection Check**. 2. Run **Build Gate**. 3. Run **Test Gate** (targeted filters + full unit test suite). 4. Apply status updates in max-15-ID chunks only. 5. Commit the task checkpoint before continuing. --- ## ANTI-STUB GUARDRAILS (NON-NEGOTIABLE) ### Forbidden Patterns The following are forbidden in Batch 39 feature/test work: - `throw new NotImplementedException()` - Empty mapped method bodies / no-op ports - `TODO` / `PLACEHOLDER` comments as unresolved implementation markers - `Assert.True(true)` / `Assert.Pass()` - Template assertions disconnected from behavior: - `var goFile = "server/..."` - `"".ShouldContain("Should")` - `GetRequiredApiLevel(new Dictionary()).ShouldBe(string.Empty)` as primary assertion - Placeholder return shortcuts in mapped code: - `=> default;` - `return default;` - `return null;` - Catch-and-ignore blocks used only to force green tests ### Hard Limits - Max feature group size: `~20`. - Max IDs per `feature batch-update`: `15`. - Max IDs per `test batch-update`: `15`. - One active feature loop at a time. - One active test loop at a time. - Mandatory checkpoint between tasks. - No `verified` promotion without checkpoint evidence. ### If You Get Stuck (REQUIRED) 1. Stop on the current feature/test immediately. 2. Do **not** stub or fake-pass. 3. Mark item `deferred` with a specific blocker reason. 4. Continue with the next unblocked item. Feature deferral: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- \ feature update --status deferred --override "blocked: " --db porting.db ``` Test deferral: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- \ test update --status deferred --override "blocked: " --db porting.db ``` `deferred` with concrete reason is the correct fallback; stubs are not. --- ## Feature Groups (max ~20 each) ### Group A (18): waiting queue and pull ingress IDs: `696,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715` ### Group B (18): dispatch core, ack floor, inbound loops IDs: `716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733` ### Group C (19): delivery, flow-control, redelivery basics IDs: `734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752` ### Group D (19): reply parsing, seq selection, identity helpers IDs: `753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,772` ### Group E (19): purge/stop/no-interest/monitor signaling IDs: `774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792` ## Test Waves ### Wave T1 (14): `NatsConsumerTests` IDs: `1230,1232,1251,1261,1265,1267,1273,1277,1283,1284,1285,1286,1339,1370` ### Wave T2 (17): `JetStreamEngineTests` (pull/ack-first half) IDs: `1469,1484,1485,1486,1487,1488,1489,1490,1492,1493,1495,1496,1498,1499,1500,1501,1502` ### Wave T3 (17): `JetStreamEngineTests` (pending/purge-second half) IDs: `1508,1514,1515,1516,1517,1518,1519,1520,1521,1522,1526,1530,1531,1545,1547,1567,1665` ### Wave T4 (5): cross-suite integration/backlog edges IDs: `814,1840,2389,2407,2858` --- ### Task 1: Preflight and Baseline **Files:** - Read: `docs/plans/2026-02-27-batch-39-consumer-dispatch-design.md` - Read: `golang/nats-server/server/consumer.go` **Steps:** 1. Run dependency preflight and confirm Batch 39 readiness. 2. Start Batch 39. 3. Capture baseline build + full unit test results. 4. Record baseline pass/fail/skip counts. ### Task 2: Implement Feature Group A + Test Wave T1 **Files:** - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Waiting.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Pull.cs` - Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/StreamTypes.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/NatsConsumerTests.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/NatsConsumerTests.Impltests.cs` **Steps:** 1. Process each feature ID in Group A through the per-feature loop. 2. Port all tests in Wave T1 with per-test loop. 3. Run checkpoint protocol. 4. Update Group A/T1 statuses in max-15-ID chunks. 5. Commit. ### Task 3: Implement Feature Group B **Files:** - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Pull.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Acks.cs` - Modify/Create: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/JetStream/NatsConsumerDispatchTests.cs` **Steps:** 1. Process Group B feature IDs through per-feature loop. 2. Add deterministic unit tests for dispatch loop and ack-floor transitions. 3. Run checkpoint protocol. 4. Update Group B feature statuses in max-15-ID chunks. 5. Commit. ### Task 4: Implement Feature Group C + Test Wave T2 **Files:** - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Delivery.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Redelivery.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamEngineTests.Impltests.cs` **Steps:** 1. Process Group C feature IDs through per-feature loop. 2. Port Wave T2 tests through per-test loop. 3. Run checkpoint protocol. 4. Update Group C/T2 statuses in max-15-ID chunks. 5. Commit. ### Task 5: Implement Feature Group D + Test Wave T3 **Files:** - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.ReplyParsing.cs` - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsStream.Consumers.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamEngineTests.Impltests.cs` **Steps:** 1. Process Group D feature IDs through per-feature loop. 2. Port Wave T3 tests through per-test loop. 3. Run checkpoint protocol. 4. Update Group D/T3 statuses in max-15-ID chunks. 5. Commit. ### Task 6: Implement Feature Group E + Test Wave T4 **Files:** - Modify/Create: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.Dispatch.Shutdown.cs` - Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/NatsConsumer.cs` - Modify/Create: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamClusterTests1.Impltests.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests1.Impltests.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JwtProcessorTests.Impltests.cs` - Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.Impltests.cs` **Steps:** 1. Process Group E feature IDs through per-feature loop. 2. Port Wave T4 tests through per-test loop. 3. Run checkpoint protocol. 4. Update Group E/T4 statuses in max-15-ID chunks. 5. Commit. ### Task 7: Final Batch 39 Verification and Closure **Files:** - Modify: `porting.db` - Generate: `reports/current.md` **Steps:** 1. Run full stub scan over changed source + test files. 2. Run full build gate. 3. Run full unit test suite; require `Failed: 0`. 4. Run: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- batch show 39 --db porting.db $DOTNET run --project tools/NatsNet.PortTracker -- report summary --db porting.db ``` 5. If all IDs are complete/verified/deferred-with-reason, execute batch completion: ```bash $DOTNET run --project tools/NatsNet.PortTracker -- batch complete 39 --db porting.db ``` 6. Generate updated report and commit: ```bash ./reports/generate-report.sh git add dotnet/src/ZB.MOM.NatsNet.Server dotnet/tests/ZB.MOM.NatsNet.Server.Tests porting.db reports/ git commit -m "feat(batch39): implement consumer dispatch features and tests" ```