# 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 3’s 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"
```
