# Batch 29 JetStream Batching Design **Date:** 2026-02-27 **Batch:** 29 (`JetStream Batching`) **Scope:** 12 features + 3 unit tests **Dependencies:** batch `27` (`JetStream Core`) **Go source:** `golang/nats-server/server/jetstream_batching.go` (+ mapped tests in `server/raft_test.go`) ## Problem Batch 29 ports JetStream atomic batch internals: batch lifecycle/store setup, staged consistency bookkeeping, apply-path rejection/cleanup, and pre-proposal header validation (`checkMsgHeadersPreClusteredProposal`). This batch also includes 3 Raft-node behavior tests that depend on batch cleanup correctness. ## Context Findings ### Required command outputs (captured) - `batch show 29 --db porting.db` - Batch 29 is `pending` - 12 features + 3 tests are all `deferred` - Dependency: batch 27 - Go file: `server/jetstream_batching.go` - `batch list --db porting.db` - Batch 29 sits after batch 28 and depends on 27 - Batch 40 (`MQTT Server/JSA`) depends on 27 as well; keeping 29 high quality prevents later churn in JetStream/Raft behavior - `report summary --db porting.db` - Features verified: 1271 / 3673 - Tests verified: 430 / 3257 - Deferred backlog remains dominant, so no-stub discipline is mandatory ### Batch 29 mapped IDs Features: - `1508` `batching.newBatchGroup` - `1509` `getBatchStoreDir` - `1510` `newBatchStore` - `1511` `batchGroup.readyForCommit` - `1512` `batchGroup.cleanup` - `1513` `batchGroup.cleanupLocked` - `1514` `batchGroup.stopLocked` - `1515` `batchStagedDiff.commit` - `1516` `batchApply.clearBatchStateLocked` - `1517` `batchApply.rejectBatchStateLocked` - `1518` `batchApply.rejectBatchState` - `1519` `checkMsgHeadersPreClusteredProposal` (largest surface, ~423 Go LOC) Tests: - `2654` `TestNRGMultipleStopsDontPanic` -> `RaftNodeTests.NRGMultipleStopsDontPanic_ShouldSucceed` - `2674` `TestNRGKeepRunningOnServerShutdown` -> `RaftNodeTests.NRGKeepRunningOnServerShutdown_ShouldSucceed` - `2718` `TestNRGInitSingleMemRaftNodeDefaults` -> `RaftNodeTests.NRGInitSingleMemRaftNodeDefaults_ShouldSucceed` ### Existing .NET baseline - `dotnet/src/ZB.MOM.NatsNet.Server/JetStream/JetStreamBatching.cs` exists but is partial and contains stub-like behavior (`ReadyForCommit` comment indicates stub). - No current `RaftNodeTests` file exists under `dotnet/tests/...`; mapped test targets are not implemented yet. - JetStream batching test file currently contains deferred placeholders and does not cover Batch 29 mapped Raft tests. ## Approaches ### Approach A: Single massive `JetStreamBatching.cs` pass in one shot - Pros: fewer commits, direct throughput. - Cons: high defect risk around cross-cutting map/counter/header logic, hard to validate incrementally. ### Approach B (Recommended): Two feature waves + one test wave with strict evidence gates - Wave 1: batch/store lifecycle primitives (`1508-1514`) - Wave 2: staged/apply/header semantics (`1515-1519`) - Wave 3: mapped Raft tests (`2654,2674,2718`) - Pros: manageable review units, easier causality between feature changes and tests, strongest anti-stub control. - Cons: more status updates/checkpoints. ### Approach C: Signature-first fill (compile now, behavior later) - Pros: quick apparent progress. - Cons: violates anti-stub goals and creates false tracker progress. Decision: **Approach B**. ## Proposed Design ### 1. Component boundaries - Keep batching logic centered in `JetStreamBatching.cs` for mapped methods. - Add narrow helper methods/types only when required to preserve method-level mapping and testability. - Keep heavy validation (`checkMsgHeadersPreClusteredProposal`) behaviorally aligned with Go checks: pre-check ordering, duplicate/msg-id checks, counter increment path, expected sequence checks, scheduling/rollup constraints, and discard policy checks. ### 2. Data and concurrency model - Preserve lock expectations from Go comments by using existing `Lock`/`ReaderWriterLockSlim` conventions. - Preserve inflight/global counters and cleanup semantics as deterministic state transitions. - Ensure timer cleanup and commit readiness are race-safe and idempotent. ### 3. Feature grouping strategy (max ~20) - **Group A (7 features):** `1508-1514` - Batch group creation, store dir/store construction, commit readiness, cleanup and stop paths. - **Group B (5 features):** `1515-1519` - Staged diff commit state, batch apply clear/reject, and full header pre-check function. ### 4. Test strategy - Create/port mapped tests in `RaftNodeTests` (or equivalent mapped class file) with real Arrange/Act/Assert behavior. - Keep tests deterministic and non-networked where possible; if runtime infrastructure is missing, explicitly defer with reason. - Add focused unit tests for `JetStreamBatching` helpers as needed to verify feature behavior before promoting feature status. ### 5. Status and evidence design - Status transitions must be evidence-backed: `stub -> complete -> verified`. - Chunked updates (max 15 IDs) to prevent bulk unverifiable promotion. - Checkpoint between tasks: stub scan + build + targeted tests + tracker updates. ## Risks and Mitigations - **Risk:** `1519` complexity causes partial/placeholder implementation. - **Mitigation:** isolate into dedicated task, require feature-level gates and explicit defer-if-blocked path. - **Risk:** Mapped Raft tests need runtime hooks not yet available. - **Mitigation:** mark `deferred` with exact blocker reason; no fake-pass tests. - **Risk:** Tracker drift from actual behavior. - **Mitigation:** per-ID evidence, max-15 update chunk, and post-task checkpoints. ## Success Criteria - All Batch 29 features and tests are either: - `verified` with captured verification evidence, or - `deferred` with explicit blocker reason. - No new stub patterns introduced in touched production/test files. - Build and relevant test gates are green at each task checkpoint. ## Non-Goals - Executing implementation in this design doc. - Refactoring unrelated JetStream or Raft subsystems beyond mapped Batch 29 behavior. - Broad integration-test harness expansion beyond what Batch 29 requires.