Files
natsnet/docs/plans/2026-02-27-batch-3-sendq-service-client-proxyproto-plan.md
Joseph Doherty b928be4f2f Add batch plans for batches 1-5 and 8 (rounds 1-3)
Generated design docs and implementation plans via Codex for:
- Batch 1: Proto, Const, CipherSuites, NKey, JWT
- Batch 2: Parser, Sublist, MemStore remainders
- Batch 3: SendQ, Service, Client ProxyProto
- Batch 4: Logging
- Batch 5: JetStream Errors
- Batch 8: Store Interfaces

All plans include mandatory verification protocol and anti-stub guardrails.
Updated batches.md with file paths and planned status.
2026-02-27 14:11:29 -05:00

510 lines
17 KiB
Markdown
Raw 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.
# Batch 3 (SendQ, Service, Client ProxyProto) Implementation Plan
> **For Codex:** REQUIRED SUB-SKILL: Use `executeplan` to implement this plan task-by-task.
**Goal:** Implement and verify Batch 3s 18 features and 1 tracked test with Go-parity behavior, zero stub leakage, and evidence-backed PortTracker status updates.
**Architecture:** Execute Batch 3 in three feature groups (ProxyProto, SendQueue, Service) plus one tracked-test group. Reuse existing .NET proxy/service behavior where valid, add compatibility surfaces for mapped Batch 3 methods, and run strict per-feature verification loops 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-3-sendq-service-client-proxyproto-design.md`
---
## Batch 3 Working Set
Feature groups (max group size <= 20 features):
- **Group A - ProxyProto (8):** `574`, `575`, `576`, `577`, `578`, `579`, `580`, `581`
- **Group B - SendQueue (3):** `2971`, `2972`, `2973`
- **Group C - Service (7):** `3148`, `3149`, `3150`, `3151`, `3152`, `3153`, `3154`
- **Tracked test (1):** `2832`
Batch facts:
- Total features: `18`
- Total tracked tests: `1`
- Dependency: `Batch 1`
- Go files: `server/client_proxyproto.go`, `server/sendq.go`, `server/service.go`, `server/service_windows.go`
> `dotnet` is not on PATH in this environment. Use `/usr/local/share/dotnet/dotnet` in all commands.
---
## MANDATORY VERIFICATION PROTOCOL
> **NON-NEGOTIABLE:** Every feature and test in this plan must follow this protocol. Skipping steps is a plan violation.
### What Counts as Real Verification
A feature or test can be marked `verified` only if all are true:
1. Go source was reviewed for the mapped ID (`feature show` or `test show` + source lines).
2. C# implementation/test contains real behavior (no placeholders/fake pass assertions).
3. Related tests execute with non-zero discovery and pass.
4. Group build gate is green.
5. Stub detection checks are clean for touched files.
### Per-Feature Verification Loop (REQUIRED for every feature ID)
1. Read mapped Go source and intent:
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- feature show <id> --db porting.db
```
2. Write/adjust C# implementation in mapped target area.
3. Build immediately after feature-level change:
```bash
/usr/local/share/dotnet/dotnet build dotnet/
```
4. Run related tests for that feature area.
5. Confirm `Passed > 0` and `Failed = 0` before adding ID to verified candidates.
### Per-Test Verification Loop (REQUIRED for test `2832`)
1. Read Go test source and dependent feature behavior:
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- test show 2832 --db porting.db
```
2. Write the C# test first (real Arrange/Act/Assert, no placeholder asserts).
3. Run the specific test filter and confirm it is discovered and passing.
4. Run containing class filter and confirm cumulative pass summary.
### Stub Detection Check (REQUIRED after each feature group and test group)
Run on touched files before any status updates:
```bash
# Forbidden markers in changed source/test files
git diff -- dotnet/src/ZB.MOM.NatsNet.Server dotnet/tests/ZB.MOM.NatsNet.Server.Tests | \
grep -nE "^\+.*(NotImplementedException|TODO|PLACEHOLDER|Assert\.True\(true\)|Assert\.Pass\(|ShouldBe\(true\);)"
# Empty method bodies introduced in touched files
for f in $(git diff --name-only -- dotnet/src/ZB.MOM.NatsNet.Server dotnet/tests/ZB.MOM.NatsNet.Server.Tests | grep -E "\.cs$"); do
grep -nE "(public|private|internal|protected).*\)\s*\{\s*\}" "$f";
done
```
Any match blocks status promotion until fixed or reclassified (`deferred`/`n_a`) with reason.
### Build Gate (REQUIRED after each feature group)
```bash
/usr/local/share/dotnet/dotnet build dotnet/
```
Required: `0` errors.
### Test Gate (REQUIRED before marking features `verified`)
All related tests for the active group must pass:
- Group A (ProxyProto):
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~ZB.MOM.NatsNet.Server.Tests.Protocol.ProxyProtocolTests" --verbosity normal
```
- Group B (SendQueue):
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~SendQueueTests" --verbosity normal
```
- Group C (Service):
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~SignalHandlerTests|FullyQualifiedName~ServiceManagerTests" --verbosity normal
```
- Group D (tracked test):
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~RoutePoolRouteStoredSameIndexBothSides_ShouldSucceed" --verbosity normal
```
### Status Update Protocol
- **Maximum 15 IDs per `batch-update` call** (hard cap).
- Do not mark `verified` without evidence bundle (Go source reference, build output, related test output, stub-scan output).
- Apply status in order: `deferred/not_started -> stub -> complete -> verified`.
- Use `n_a` only with explicit technical justification.
Examples:
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "574,575,576,577,578,579,580,581" --set-status stub --db porting.db --execute
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "574,575,576,577,578,579,580,581" --set-status complete --db porting.db --execute
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "574,575,576,577,578,579,580,581" --set-status verified --db porting.db --execute
```
For blocked items:
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature update <id> --status deferred --db porting.db --override "blocked: <specific reason>"
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature update <id> --status n_a --db porting.db --override "n/a: <specific reason>"
```
### Checkpoint Protocol Between Tasks (REQUIRED)
After each task group and before starting the next:
1. Full build:
```bash
/usr/local/share/dotnet/dotnet build dotnet/
```
2. Full unit tests:
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --verbosity normal
```
3. Confirm no regressions introduced.
4. Commit task-scoped changes (including `porting.db`) before proceeding.
---
## ANTI-STUB GUARDRAILS (NON-NEGOTIABLE)
### Forbidden Patterns
These are forbidden in feature or test changes for Batch 3:
- `throw new NotImplementedException()`
- `TODO` / `PLACEHOLDER` markers in newly added code
- Empty method body placeholders (`{ }`) for mapped features
- Fake pass assertions (`Assert.True(true)`, `Assert.Pass()`, meaningless sentinel assertions)
- Default/null return used only to satisfy compiler with no Go-equivalent behavior
- Test methods with no production call + no meaningful assertion
### Hard Limits
- Max `15` IDs per status update command.
- Max `1` feature group promoted per verification cycle.
- Mandatory `build` + related `test` gate before `verified`.
- Mandatory stub scan before every status promotion.
- Mandatory checkpoint commit between groups.
### If You Get Stuck (REQUIRED behavior)
Do not stub and do not fake-pass.
1. Keep item as `deferred` (or `n_a` only if genuinely non-applicable).
2. Add explicit reason with `--override` in PortTracker.
3. Commit only proven work.
4. Continue with next unblocked ID.
---
### Task 1: Group A - Proxy Protocol Features (`574-581`)
**Files:**
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/ClientConnection.cs`
- Create: `dotnet/src/ZB.MOM.NatsNet.Server/ClientConnection.ProxyProto.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/Protocol/ProxyProtocol.cs`
- Modify/Test: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Protocol/ProxyProtocolTests.cs`
**Step 1: Mark Group A features as `stub`**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "574,575,576,577,578,579,580,581" --set-status stub --db porting.db --execute
```
**Step 2: Write/adjust failing tests first**
Add coverage for any missing mapped behavior:
- `RemoteAddr` mapped semantics
- version detect wrappers
- v1/v2 parser wrapper entry points
- IPv4/IPv6 parse wrappers
**Step 3: Run focused ProxyProto tests (expect fail first, then pass)**
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~ProxyProtocolTests" --verbosity normal
```
**Step 4: Implement minimal production parity**
- Add `ClientConnection` mapped method shims to existing parser core.
- Keep parsing logic centralized in `Protocol/ProxyProtocol.cs`.
**Step 5: Re-run focused tests until green**
Use Step 3 command.
**Step 6: Run stub detection + build gate**
Run protocol checks.
**Step 7: Promote statuses (`complete`, then `verified`)**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "574,575,576,577,578,579,580,581" --set-status complete --db porting.db --execute
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "574,575,576,577,578,579,580,581" --set-status verified --db porting.db --execute
```
**Step 8: Checkpoint protocol + commit**
```bash
git add dotnet/src/ZB.MOM.NatsNet.Server/ClientConnection.cs \
dotnet/src/ZB.MOM.NatsNet.Server/ClientConnection.ProxyProto.cs \
dotnet/src/ZB.MOM.NatsNet.Server/Protocol/ProxyProtocol.cs \
dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Protocol/ProxyProtocolTests.cs \
porting.db
git commit -m "feat(batch3): verify client proxy protocol feature group"
```
---
### Task 2: Group B - SendQueue Features (`2971-2973`)
**Files:**
- Create: `dotnet/src/ZB.MOM.NatsNet.Server/SendQueue.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/NatsServer.Accounts.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/Accounts/Account.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/ClientConnection.cs`
- Create/Test: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/SendQueueTests.cs`
**Step 1: Mark Group B features as `stub`**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "2971,2972,2973" --set-status stub --db porting.db --execute
```
**Step 2: Write failing tests first**
Cover at minimum:
- `NewSendQ` creates queue and starts loop entry path
- `Send` no-ops when queue is null/disposed
- queued messages are copied and passed to internal client path
**Step 3: Run focused SendQueue tests (expect fail first, then pass)**
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~SendQueueTests" --verbosity normal
```
**Step 4: Implement minimal SendQueue parity**
- Port `newSendQ`, `internalLoop`, `send` intent using `IpQueue<T>` + existing internal client APIs.
- Replace `Account.SendQueue` placeholder with concrete type usage.
**Step 5: Re-run focused tests until green**
Use Step 3 command.
**Step 6: Run stub detection + build gate**
Run protocol checks.
**Step 7: Promote statuses (`complete`, then `verified`)**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "2971,2972,2973" --set-status complete --db porting.db --execute
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "2971,2972,2973" --set-status verified --db porting.db --execute
```
**Step 8: Checkpoint protocol + commit**
```bash
git add dotnet/src/ZB.MOM.NatsNet.Server/SendQueue.cs \
dotnet/src/ZB.MOM.NatsNet.Server/NatsServer.Accounts.cs \
dotnet/src/ZB.MOM.NatsNet.Server/Accounts/Account.cs \
dotnet/src/ZB.MOM.NatsNet.Server/ClientConnection.cs \
dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/SendQueueTests.cs \
porting.db
git commit -m "feat(batch3): implement send queue feature group"
```
---
### Task 3: Group C - Service Features (`3148-3154`)
**Files:**
- Create: `dotnet/src/ZB.MOM.NatsNet.Server/Internal/ServiceManager.cs`
- Create (if needed): `dotnet/src/ZB.MOM.NatsNet.Server/Internal/ServiceManager.Windows.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/Internal/SignalHandler.cs`
- Create/Test: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/ServiceManagerTests.cs`
- Modify/Test: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/SignalHandlerTests.cs`
**Step 1: Mark Group C features as `stub`**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "3148,3149,3150,3151,3152,3153,3154" --set-status stub --db porting.db --execute
```
**Step 2: Write failing tests first**
Cover:
- non-Windows `Run` behavior
- non-Windows `IsWindowsService` behavior
- service-name configuration behavior (if implemented)
- Windows-only hooks either behaviorally verified or explicitly marked `n_a`
**Step 3: Run focused service tests (expect fail first, then pass)**
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~SignalHandlerTests|FullyQualifiedName~ServiceManagerTests" --verbosity normal
```
**Step 4: Implement service parity layer**
- Add `ServiceManager` mapped surface.
- For Windows-only features (`3150-3154`), choose one per-ID outcome based on evidence:
- implemented wrapper (`complete/verified`), or
- `n_a` with explicit reason tied to host-level WindowsService ownership.
**Step 5: Re-run focused tests until green**
Use Step 3 command.
**Step 6: Run stub detection + build gate**
Run protocol checks.
**Step 7: Promote statuses with evidence**
- Use `complete` -> `verified` for implemented service features.
- Use `n_a` for validated non-applicable Windows-host-only entries.
- Keep max 7 IDs in this task update (below 15 cap).
**Step 8: Checkpoint protocol + commit**
```bash
git add dotnet/src/ZB.MOM.NatsNet.Server/Internal/ServiceManager.cs \
dotnet/src/ZB.MOM.NatsNet.Server/Internal/ServiceManager.Windows.cs \
dotnet/src/ZB.MOM.NatsNet.Server/Internal/SignalHandler.cs \
dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/ServiceManagerTests.cs \
dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/SignalHandlerTests.cs \
porting.db
git commit -m "feat(batch3): implement service feature group"
```
---
### Task 4: Group D - Tracked Test `2832`
**Files:**
- Modify/Test: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.Impltests.cs`
- Modify (only if required by real behavior): `dotnet/src/ZB.MOM.NatsNet.Server/Routes/*`
**Step 1: Mark test `2832` as `stub`**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
test update 2832 --status stub --db porting.db
```
**Step 2: Write real failing test first**
Implement `RoutePoolRouteStoredSameIndexBothSides_ShouldSucceed` with actual route index/endpoint assertions mirroring Go intent.
**Step 3: Run focused test and class gates**
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~RoutePoolRouteStoredSameIndexBothSides_ShouldSucceed" --verbosity normal
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~RouteHandlerTests" --verbosity normal
```
**Step 4: If infrastructure is missing, defer explicitly (do not stub)**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
test update 2832 --status deferred --db porting.db \
--override "blocked: requires route-pool runtime topology not yet implemented in current server core"
```
**Step 5: If test is green, promote to `verified`**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
test update 2832 --status verified --db porting.db
```
**Step 6: Checkpoint protocol + commit**
```bash
git add dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.Impltests.cs \
dotnet/src/ZB.MOM.NatsNet.Server/Routes \
porting.db
git commit -m "test(batch3): handle route pool same-index test"
```
---
### Task 5: Batch 3 Closure
**Files:**
- Modify: `porting.db`
- Generate: `reports/current.md` (via report script)
**Step 1: Verify batch state**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch show 3 --db porting.db
```
Required: all 18 features and test `2832` are `verified`/`complete`/`n_a`; unresolved blockers remain explicitly `deferred` with reason.
**Step 2: Full regression gate**
```bash
/usr/local/share/dotnet/dotnet build dotnet/
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --verbosity normal
```
Required: `Failed: 0` for full unit test suite.
**Step 3: Complete batch if eligible**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch complete 3 --db porting.db
```
**Step 4: Validate summary + readiness**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- report summary --db porting.db
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- dependency ready --db porting.db
```
**Step 5: Generate report and final commit**
```bash
./reports/generate-report.sh
git add porting.db reports/current.md
git commit -m "chore(batch3): close sendq-service-proxyproto batch"
```