# 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 --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 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 --status deferred --db porting.db \ --override "blocked: requires 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 ` 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~" --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" ```