# Batch 14 FileStore Write/Lifecycle Implementation Plan

> **For Codex:** REQUIRED SUB-SKILL: Use `executeplan` to implement this plan task-by-task.

**Goal:** Implement and verify all Batch 14 FileStore write/lifecycle features and mapped tests from `server/filestore.go` with non-stub behavior and evidence-backed status transitions.

**Architecture:** Execute Batch 14 in four vertical feature groups (`18 + 18 + 20 + 20`) aligned to `filestore.go` locality and lifecycle boundaries. After each feature group, run strict stub/build/test gates, then port and verify the dependency-resolved test wave before any `verified` status changes. Keep implementation centered in `JetStream/FileStore.cs`, with targeted support updates in `MessageBlock.cs` and `FileStoreTypes.cs` only when required by Go parity.

**Tech Stack:** .NET 10, C# latest, xUnit 3, Shouldly, NSubstitute, PortTracker CLI, SQLite (`porting.db`)

---

I'm using `writeplan` to create the implementation plan.

**Design doc:** `docs/plans/2026-02-27-batch-14-filestore-write-lifecycle-design.md`

## Batch Inputs

- Batch: `14` (`FileStore Write/Lifecycle`)
- Depends on: Batch `13`
- Features: `76`
- Tests: `64`
- Go source: `golang/nats-server/server/filestore.go`

Feature groups (max ~20 each):

- Group 1 (`18`): `1020,1024,1027,1028,1029,1036,1037,1038,1039,1040,1041,1042,1045,1046,1047,1048,1054,1066`
- Group 2 (`18`): `1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1099,1100,1101,1102,1108,1109,1110,1111`
- Group 3 (`20`): `1131,1132,1133,1139,1140,1147,1148,1160,1161,1162,1168,1169,1171,1172,1178,1179,1180,1181,1182,1183`
- Group 4 (`20`): `1184,1189,1193,1195,1197,1198,1199,1201,1202,1203,1204,1205,1207,1208,1210,1211,1212,1214,1215,1260`

Test waves (dependency-resolved):

- Wave 1 (`8`): `549,551,561,572,586,587,1219,2441`
- Wave 2 (`6`): `354,365,372,435,593,2476`
- Wave 3 (`27`): `363,378,418,437,438,442,452,455,457,461,462,464,470,475,476,485,490,491,492,494,495,496,498,501,503,523,2480`
- Wave 4 (`23`): `384,412,413,477,483,518,519,530,531,566,567,588,589,590,594,1899,1900,1901,1984,2001,2431,2494,2854`

Primary test files:

- `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamFileStoreTests.Impltests.cs`
- `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests1.Impltests.cs`
- `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests2.Impltests.cs`
- `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/LeafNodeHandlerTests.Impltests.cs`
- `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.Impltests.cs`
- Create if missing:
  - `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/LeafNodeProxyTests.Impltests.cs`
  - `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamClusterLongTests.Impltests.cs`

---

## MANDATORY VERIFICATION PROTOCOL

> **NON-NEGOTIABLE:** Every feature/test task and every status update must pass this protocol.

### Per-Feature Verification Loop (REQUIRED for every feature ID)

For each active feature ID:

1. Read feature mapping and Go intent:
   ```bash
   /usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- feature show <FEATURE_ID> --db porting.db
   ```
2. Read exact Go method body and nearby helpers in `golang/nats-server/server/filestore.go`.
3. Write minimal real C# behavior in FileStore/MessageBlock/FileStoreTypes.
4. Build immediately:
   ```bash
   /usr/local/share/dotnet/dotnet build dotnet/
   ```
5. Run targeted related tests for that behavior (single method or tight class filter).
6. Only then add the feature ID to status-update candidates.

### Stub Detection Check (REQUIRED after each feature group and test wave)

Any match below is a blocker:

```bash
# Production stubs/placeholders
rg -n "NotImplementedException|TODO|PLACEHOLDER|throw new NotSupportedException" \
  dotnet/src/ZB.MOM.NatsNet.Server/JetStream -g '*.cs'

# Empty production bodies on FileStore surface
rg -n "^\s*(public|private|internal|protected).*(\)\s*\{\s*\}|=>\s*default;|=>\s*null;)" \
  dotnet/src/ZB.MOM.NatsNet.Server/JetStream/FileStore.cs \
  dotnet/src/ZB.MOM.NatsNet.Server/JetStream/MessageBlock.cs

# Test placeholders and always-pass patterns
rg -n "NotImplementedException|Assert\.True\(true\)|Assert\.Pass|// TODO|// PLACEHOLDER|ShouldBe\(true\);" \
  dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/*.cs

# Existing placeholder-template smell (must be removed from ported tests)
rg -n "goFile\.ShouldStartWith\(\"server/\"\)|ServerConstants\.DefaultPort\.ShouldBe\(4222\)" \
  dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/*.cs
```

### Build Gate (REQUIRED after each feature group)

Before any status update for that group:

```bash
/usr/local/share/dotnet/dotnet build dotnet/
```

Build must pass with zero errors.

### Test Gate (REQUIRED before marking features verified)

All related tests for the active scope must pass before any feature in that scope can be marked `verified`.

Minimum gate commands:

```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
  --filter "FullyQualifiedName~ZB.MOM.NatsNet.Server.Tests.ImplBacklog.JetStreamFileStoreTests" \
  --verbosity normal

/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
  --filter "FullyQualifiedName~ZB.MOM.NatsNet.Server.Tests.ImplBacklog.ConcurrencyTests1|FullyQualifiedName~ZB.MOM.NatsNet.Server.Tests.ImplBacklog.ConcurrencyTests2|FullyQualifiedName~ZB.MOM.NatsNet.Server.Tests.ImplBacklog.LeafNodeHandlerTests|FullyQualifiedName~ZB.MOM.NatsNet.Server.Tests.ImplBacklog.LeafNodeProxyTests|FullyQualifiedName~ZB.MOM.NatsNet.Server.Tests.ImplBacklog.RouteHandlerTests|FullyQualifiedName~ZB.MOM.NatsNet.Server.Tests.ImplBacklog.JetStreamClusterLongTests" \
  --verbosity normal
```

### Status Update Protocol (REQUIRED)

- Max `15` IDs per `feature batch-update` or `test batch-update` command.
- Required progression:
  - Features: `deferred -> stub -> complete -> verified`
  - Tests: `deferred -> stub -> verified` (or stay `deferred` with reason)
- Evidence is mandatory before each update:
  - Go method reviewed
  - build passed
  - related tests passed
  - stub scan clean
- Keep evidence logs under `/tmp/batch14-evidence/`.

Example update command:

```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
  feature batch-update --ids "1020,1024,1027" --set-status complete --db porting.db --execute
```

### Checkpoint Protocol Between Tasks (REQUIRED)

Between each feature/test group transition:

1. Full build:
   ```bash
   /usr/local/share/dotnet/dotnet build dotnet/
   ```
2. Full unit suite:
   ```bash
   /usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --verbosity normal
   ```
3. Commit checkpoint:
   ```bash
   git add dotnet/src/ZB.MOM.NatsNet.Server/JetStream \
     dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog \
     porting.db
   git commit -m "feat(batch14): complete group <N> filestore write lifecycle"
   ```

---

## ANTI-STUB GUARDRAILS

### Forbidden Patterns

Do not introduce or keep any of these in Batch 14 feature/test scope:

- `throw new NotImplementedException(...)`
- Empty mapped method bodies (`{ }`) in `FileStore.cs`/`MessageBlock.cs`
- `TODO`/`PLACEHOLDER` markers in implemented methods/tests
- Always-pass tests (`Assert.True(true)`, `Assert.Pass`, trivial constants-only assertions)
- Placeholder-template tests that only validate static constants or method names
- Tests with no production behavior act step against FileStore APIs

### Hard Limits

- Max ~20 features per implementation group (fixed at `18/18/20/20`)
- Max `15` IDs per status update command
- Max one feature group per status-update cycle
- Zero stub-scan hits before `complete` or `verified`
- No `verified` transition without Build Gate + Test Gate evidence

### If You Get Stuck (MANDATORY)

1. Do not write stubs, no-ops, or fake pass tests.
2. Mark only blocked IDs as `deferred` with concrete reason.
3. Continue with unblocked IDs in the same group.
4. Record blocker evidence and use override reason text.

Example:

```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
  feature update <ID> --status deferred --db porting.db \
  --override "blocked: requires <specific infra/dependency> for non-stub implementation"
```

Use same pattern for tests.

---

### Task 1: Batch Start, Baseline, and Staging

**Files:**
- Modify: `porting.db`
- Create: `/tmp/batch14-evidence/`

**Step 1: Confirm batch state**

```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch show 14 --db porting.db
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch list --db porting.db
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- report summary --db porting.db
```

Expected: Batch 14 pending with dependency on 13.

**Step 2: Start batch**

```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch start 14 --db porting.db
```

**Step 3: Stage Group 1 IDs to stub**

Run chunked updates (`<=15 IDs` each) for Group 1 features and Wave 1 tests.

**Step 4: Baseline build/test**

```bash
/usr/local/share/dotnet/dotnet build dotnet/
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --verbosity normal
```

**Step 5: Commit baseline checkpoint**

```bash
git add porting.db docs/plans/2026-02-27-batch-14-filestore-write-lifecycle-design.md docs/plans/2026-02-27-batch-14-filestore-write-lifecycle-plan.md
git commit -m "plan(batch14): establish filestore write lifecycle execution baseline"
```

### Task 2: Implement Group 1 Features (18 IDs)

**Files:**
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/FileStore.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/MessageBlock.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/FileStoreTypes.cs`

**Step 1: Port write-path foundations**

Feature IDs: `1020,1024,1027,1028,1029`

**Step 2: Port sequence and limit/removal paths**

Feature IDs: `1036,1037,1038,1039,1040,1041,1042,1045,1046,1047,1048,1054,1066`

**Step 3: Apply mandatory verification protocol**

Run per-feature loop, stub scans, and build gate for all 18 IDs.

**Step 4: Update Group 1 feature status**

- Move to `complete` in chunks <=15.
- Move to `verified` only after Wave 1 test gate passes.

### Task 3: Port and Verify Wave 1 Tests (8 IDs)

**Files:**
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamFileStoreTests.Impltests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests1.Impltests.cs`
- Create: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamClusterLongTests.Impltests.cs`

**Wave 1 IDs:** `549,551,561,572,586,587,1219,2441`

**Step 1: Read Go tests via `test show <ID>` and implement real behavior tests**

**Step 2: Run each test method individually, verify discovery and pass**

```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
  --filter "FullyQualifiedName~<TestMethodName>" --verbosity normal
```

**Step 3: Run class-level test gates for modified classes**

**Step 4: Run stub scans and build gate**

**Step 5: Update Wave 1 test statuses to verified (<=15 IDs per command)**

### Task 4: Group 1 Checkpoint

**Files:**
- Modify: `porting.db`

**Step 1: Run checkpoint protocol**

**Step 2: Commit Group 1 checkpoint**

```bash
git add dotnet/src/ZB.MOM.NatsNet.Server/JetStream dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog porting.db
git commit -m "feat(batch14): complete group1 write path and wave1 tests"
```

### Task 5: Implement Group 2 Features (18 IDs)

**Files:**
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/FileStore.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/MessageBlock.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/FileStoreTypes.cs`

**Feature IDs:** `1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1099,1100,1101,1102,1108,1109,1110,1111`

**Step 1: Port age-check, scheduling, and check/flush loops**

**Step 2: Port message record/tombstone and block sync/select helpers**

**Step 3: Apply mandatory verification protocol**

**Step 4: Update Group 2 feature statuses (chunked <=15)**

### Task 6: Port and Verify Wave 2 Tests (6 IDs)

**Files:**
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamFileStoreTests.Impltests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests2.Impltests.cs`

**Wave 2 IDs:** `354,365,372,435,593,2476`

**Step 1: Implement tests from Go source intent**

**Step 2: Execute per-test loop + class-level gate**

**Step 3: Run stub scans/build gate and verify no placeholder-template remnants**

**Step 4: Mark Wave 2 tests verified (<=15 IDs per call)**

### Task 7: Group 2 Checkpoint

**Files:**
- Modify: `porting.db`

**Step 1: Run checkpoint protocol**

**Step 2: Commit Group 2 checkpoint**

```bash
git add dotnet/src/ZB.MOM.NatsNet.Server/JetStream dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog porting.db
git commit -m "feat(batch14): complete group2 lifecycle checks and wave2 tests"
```

### Task 8: Implement Group 3 Features (20 IDs)

**Files:**
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/FileStore.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/MessageBlock.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/FileStoreTypes.cs`

**Feature IDs:** `1131,1132,1133,1139,1140,1147,1148,1160,1161,1162,1168,1169,1171,1172,1178,1179,1180,1181,1182,1183`

**Step 1: Port seq/message/load helpers and cache/state accessors**

**Step 2: Port purge/compact/reset and block list management methods**

**Step 3: Apply mandatory verification protocol**

**Step 4: Update Group 3 feature statuses (<=15 IDs per command)**

### Task 9: Port and Verify Wave 3 Tests (27 IDs)

**Files:**
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamFileStoreTests.Impltests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests2.Impltests.cs`

**Wave 3 IDs:** `363,378,418,437,438,442,452,455,457,461,462,464,470,475,476,485,490,491,492,494,495,496,498,501,503,523,2480`

**Step 1: Implement tests in sub-batches of 10-12 methods**

**Step 2: For each sub-batch, run per-test loop and class gate**

**Step 3: Run mandatory stub/build/test gates**

**Step 4: Mark Wave 3 tests verified in max-15 ID chunks**

### Task 10: Group 3 Checkpoint

**Files:**
- Modify: `porting.db`

**Step 1: Run checkpoint protocol**

**Step 2: Commit Group 3 checkpoint**

```bash
git add dotnet/src/ZB.MOM.NatsNet.Server/JetStream dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog porting.db
git commit -m "feat(batch14): complete group3 purge compact state and wave3 tests"
```

### Task 11: Implement Group 4 Features (20 IDs)

**Files:**
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/FileStore.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/MessageBlock.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/FileStoreTypes.cs`

**Feature IDs:** `1184,1189,1193,1195,1197,1198,1199,1201,1202,1203,1204,1205,1207,1208,1210,1211,1212,1214,1215,1260`

**Step 1: Port purge-block/global subject info and stream-state write loops**

**Step 2: Port stop/snapshot/read-lock-all/delete-map/delete-blocks/write-file-with-optional-sync lifecycle methods**

**Step 3: Apply mandatory verification protocol**

**Step 4: Update Group 4 feature statuses (<=15 IDs per command)**

### Task 12: Port and Verify Wave 4 Tests (23 IDs)

**Files:**
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamFileStoreTests.Impltests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/LeafNodeHandlerTests.Impltests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests1.Impltests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests2.Impltests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.Impltests.cs`
- Create: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/LeafNodeProxyTests.Impltests.cs`

**Wave 4 IDs:** `384,412,413,477,483,518,519,530,531,566,567,588,589,590,594,1899,1900,1901,1984,2001,2431,2494,2854`

**Step 1: Implement file-store lifecycle tests in `JetStreamFileStoreTests.Impltests.cs`**

**Step 2: Implement cross-module backlog tests (leaf/proxy/route/concurrency) only with real behavior assertions**

**Step 3: If any test requires unavailable infra, mark that test `deferred` with explicit reason (no stubs)**

**Step 4: Run per-test loop, class gates, stub scans, and build gate**

**Step 5: Mark verified/deferred statuses in <=15 ID chunks with evidence**

### Task 13: Final Verification, Audit, and Batch Closure

**Files:**
- Modify: `porting.db`
- Generate: `reports/current.md`

**Step 1: Full regression gates**

```bash
/usr/local/share/dotnet/dotnet build dotnet/
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --verbosity normal
```

**Step 2: Global stub audit (features + tests)**

```bash
rg -n "NotImplementedException|TODO|PLACEHOLDER|Assert\.True\(true\)|Assert\.Pass|goFile\.ShouldStartWith\(\"server/\"\)" \
  dotnet/src/ZB.MOM.NatsNet.Server/JetStream \
  dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog
```

**Step 3: Run PortTracker audits**

```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- audit --type features --db porting.db
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- audit --type tests --db porting.db
```

**Step 4: Verify batch visibility and complete**

```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch show 14 --db porting.db
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch complete 14 --db porting.db
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- report summary --db porting.db
```

**Step 5: Generate report and final commit**

```bash
./reports/generate-report.sh
git add dotnet/src/ZB.MOM.NatsNet.Server/JetStream dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog porting.db reports/
git commit -m "feat(batch14): complete filestore write lifecycle features and tests"
```
