Files
natsdotnet/gaps/raft.md
Joseph Doherty c30e67a69d Fix E2E test gaps and add comprehensive E2E + parity test suites
- Fix pull consumer fetch: send original stream subject in HMSG (not inbox)
  so NATS client distinguishes data messages from control messages
- Fix MaxAge expiry: add background timer in StreamManager for periodic pruning
- Fix JetStream wire format: Go-compatible anonymous objects with string enums,
  proper offset-based pagination for stream/consumer list APIs
- Add 42 E2E black-box tests (core messaging, auth, TLS, accounts, JetStream)
- Add ~1000 parity tests across all subsystems (gaps closure)
- Update gap inventory docs to reflect implementation status
2026-03-12 14:09:23 -04:00

34 KiB

RAFT — Gap Analysis

This file tracks what has and hasn't been ported from Go to .NET for the RAFT module. See stillmissing.md for the full LOC comparison across all modules.

LLM Instructions: How to Analyze This Category

Step 1: Read the Go Reference Files

Read each Go source file listed below. For every file:

  1. Extract all exported types (structs, interfaces, type aliases)
  2. Extract all exported methods on those types (receiver functions)
  3. Extract all exported standalone functions
  4. Note key constants, enums, and protocol states
  5. Note important unexported helpers that implement core logic (functions >20 lines)
  6. Pay attention to concurrency patterns (goroutines, mutexes, channels) — these map to different .NET patterns

Step 2: Read the .NET Implementation Files

Read all .cs files in the .NET directories listed below. For each Go symbol found in Step 1:

  1. Search for a matching type, method, or function in .NET
  2. If found, compare the behavior: does it handle the same edge cases? Same error paths?
  3. If partially implemented, note what's missing
  4. If not found, note it as MISSING

Step 3: Cross-Reference Tests

Compare Go test functions against .NET test methods:

  1. For each Go Test* function, check if a corresponding .NET [Fact] or [Theory] exists
  2. Note which test scenarios are covered and which are missing
  3. Check the parity DB (docs/test_parity.db) for existing mappings:
    sqlite3 docs/test_parity.db "SELECT go_test, dotnet_test, confidence FROM test_mappings tm JOIN go_tests gt ON tm.go_test_id=gt.rowid JOIN dotnet_tests dt ON tm.dotnet_test_id=dt.rowid WHERE gt.go_file LIKE '%PATTERN%'"
    

Step 4: Classify Each Item

Use these status values:

Status Meaning
PORTED Equivalent exists in .NET with matching behavior
PARTIAL .NET implementation exists but is incomplete (missing edge cases, error handling, or features)
MISSING No .NET equivalent found — needs to be ported
NOT_APPLICABLE Go-specific pattern that doesn't apply to .NET (build tags, platform-specific goroutine tricks, etc.)
DEFERRED Intentionally skipped for now (document why)

Step 5: Fill In the Gap Inventory

Add rows to the Gap Inventory table below. Group by Go source file. Include the Go file and line number so a porting LLM can jump directly to the reference implementation.

Key Porting Notes for RAFT

  • RAFT is used for JetStream cluster consensus — both meta-cluster (stream/consumer placement) and per-stream/consumer groups.
  • Key operations: leader election, log append/commit, snapshotting, peer management.
  • The .NET implementation (20 files, 3,045 LOC) is more granular than Go's single file. Check if the decomposition covers all RAFT states.

Go Reference Files (Source)

  • golang/nats-server/server/raft.go — RAFT consensus for clustered JetStream (~5,037 lines). Meta-cluster for metadata, per-stream/consumer RAFT groups. Leader election, log replication, snapshotting.

Go Reference Files (Tests)

  • golang/nats-server/server/raft_test.go
  • golang/nats-server/server/raft_helpers_test.go
  • golang/nats-server/server/raft_chain_of_blocks_helpers_test.go

.NET Implementation Files (Source)

  • src/NATS.Server/Raft/ (all 20 files)

.NET Implementation Files (Tests)

  • tests/NATS.Server.Tests/Raft/

Gap Inventory

golang/nats-server/server/raft.go — Exported Interfaces & Types

Go Symbol Go File:Line Status .NET Equivalent Notes
RaftNode (interface) raft.go:40-92 PARTIAL src/NATS.Server/Raft/IRaftNode.cs:5 Interface declared but empty — none of the 40+ methods from Go are defined
RaftNodeCheckpoint (interface) raft.go:98-103 PARTIAL src/NATS.Server/Raft/RaftSnapshotCheckpoint.cs:7 Chunk assembly exists but LoadLastSnapshot, AppendEntriesSeq, Abort, InstallSnapshot not matching Go's interface contract
WAL (interface) raft.go:105-118 PARTIAL src/NATS.Server/Raft/RaftWal.cs:20 .NET RaftWal is a concrete file-based WAL; does not implement Go's WAL interface (StoreMsg, LoadMsg, RemoveMsg, Compact, Purge, Truncate, State, FastState, Stop, Delete)
Peer (struct) raft.go:120-125 PORTED src/NATS.Server/Raft/RaftPeerState.cs Added missing parity fields (Lag, Current) plus helpers to recalculate lag and refresh current-state from heartbeat/contact timing
RaftState (enum) raft.go:127-135 PORTED src/NATS.Server/Raft/RaftState.cs:4 All four states: Follower, Leader, Candidate, Closed
RaftState.String() raft.go:137-149 PORTED src/NATS.Server/Raft/RaftStateExtensions.cs:9 Added Go-style RaftState.String() extension mapping to Follower/Leader/Candidate/Closed
RaftConfig (struct) raft.go:301-317 PORTED src/NATS.Server/Raft/RaftConfig.cs:8 Added RaftConfig model with Name/Store/Log/Track/Observer/Recovering/ScaleUp fields for parity shape
CommittedEntry (struct) raft.go:2506-2509 PORTED src/NATS.Server/Raft/CommitQueue.cs (CommittedEntry) Added explicit committed-entry shape with Index and Entries list for parity with Go commit delivery payload
Entry (struct) raft.go:2641-2644 PORTED src/NATS.Server/Raft/RaftEntry.cs Added general RaftEntry model (Type, Data) with conversion helpers to/from wire-entry shape
EntryType (enum) raft.go:2605-2619 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:54-63 All types present including EntryCatchup (mapped as RaftEntryType)

golang/nats-server/server/raft.go — Exported RaftNode Interface Methods

Go Symbol Go File:Line Status .NET Equivalent Notes
Propose() raft.go:909-924 PARTIAL src/NATS.Server/Raft/RaftNode.cs:308 ProposeAsync exists but synchronous replication model, no write-error checking, no proposal queue
ProposeMulti() raft.go:928-945 PORTED src/NATS.Server/Raft/RaftNode.cs (ProposeMultiAsync) Added ordered multi-command proposal API returning committed indexes per input command
ForwardProposal() raft.go:949-959 PARTIAL src/NATS.Server/Raft/NatsRaftTransport.cs:182 Transport has ForwardProposal but RaftNode does not call it automatically for non-leaders
InstallSnapshot() raft.go:1295-1311 PARTIAL src/NATS.Server/Raft/RaftNode.cs:699 InstallSnapshotAsync exists but no checkpointing, no WAL compaction, no highwayhash verification
CreateSnapshotCheckpoint() raft.go:1356-1360 PARTIAL src/NATS.Server/Raft/RaftNode.cs:519 CreateSnapshotCheckpointAsync exists but simplified — no async write, no WAL compaction tracking
SendSnapshot() raft.go:1284-1290 MISSING No direct snapshot send as append entry
NeedSnapshot() raft.go:1551-1555 MISSING No equivalent check
Applied() raft.go:1183-1185 PORTED src/NATS.Server/Raft/RaftNode.cs:403 Added Applied(long) callback returning (entries,bytes) and delegating progress to processed tracking
Processed() raft.go:1193-1240 PARTIAL src/NATS.Server/Raft/RaftNode.cs:664 MarkProcessed exists but much simpler — no aflr signaling, no leader state transition, no byte estimation
State() raft.go:2025-2027 PORTED src/NATS.Server/Raft/RaftNode.cs:43 Role property (uses RaftRole enum instead of RaftState)
Size() raft.go:2037-2043 PORTED src/NATS.Server/Raft/RaftNode.cs:771 Added Size() accessor returning entry count and UTF-8 command-byte estimate from current log contents
Progress() raft.go:2030-2034 PORTED src/NATS.Server/Raft/RaftNode.cs:765 Added Progress() accessor returning (index, commit, applied)
Leader() raft.go:1712-1717 PORTED src/NATS.Server/Raft/RaftNode.cs:42 IsLeader property
LeaderSince() raft.go:1721-1726 PORTED src/NATS.Server/Raft/RaftNode.cs:63 Added nullable LeaderSince timestamp and leadership transition updates
Quorum() raft.go:3070-3083 PARTIAL src/NATS.Server/Raft/RaftNode.cs:201 HasQuorum() exists but uses different window calculation (2x electionTimeout vs Go's lostQuorumInterval)
Current() raft.go:1840-1847 PARTIAL src/NATS.Server/Raft/RaftNode.cs:879 IsCurrent exists but no commit==applied check, no forward-progress polling
Healthy() raft.go:1850-1857 PARTIAL src/NATS.Server/Raft/RaftNode.cs:892 IsHealthy exists but different semantics — checks peer responsiveness, not isCurrent(true)
Term() raft.go:3119-3123 PORTED src/NATS.Server/Raft/RaftNode.cs:41 Term property
Leaderless() raft.go:1876-1883 PORTED src/NATS.Server/Raft/RaftNode.cs:65 Added lock-free Leaderless derived from tracked group leader state
GroupLeader() raft.go:1865-1872 PORTED src/NATS.Server/Raft/RaftNode.cs:64 Added GroupLeader tracking, updated on election/heartbeat/stepdown
HadPreviousLeader() raft.go:1860-1862 PORTED src/NATS.Server/Raft/RaftNode.cs:66 Added HadPreviousLeader flag that remains true after first observed leader
StepDown() raft.go:1900-1977 PARTIAL src/NATS.Server/Raft/RaftNode.cs:706 RequestStepDown exists but no preferred leader selection, no leader transfer, no EntryLeaderTransfer
SetObserver() raft.go:2394-2396 PORTED src/NATS.Server/Raft/RaftNode.cs:799 Added SetObserver(bool) toggle for observer mode
IsObserver() raft.go:2387-2391 PORTED src/NATS.Server/Raft/RaftNode.cs:68 Added IsObserver accessor
Campaign() raft.go:1980-1984 PARTIAL src/NATS.Server/Raft/RaftNode.cs:771 CampaignImmediately exists but no random campaign timeout
CampaignImmediately() raft.go:1987-1993 PORTED src/NATS.Server/Raft/RaftNode.cs:771 CampaignImmediately()
ID() raft.go:2045-2051 PORTED src/NATS.Server/Raft/RaftNode.cs:40 Id property
Group() raft.go:2053-2056 PORTED src/NATS.Server/Raft/RaftNode.cs:42 Added GroupName tracking on RaftNode with constructor support; defaults to node ID when unspecified
Peers() raft.go:2058-2077 PARTIAL src/NATS.Server/Raft/RaftNode.cs:872 GetPeerStates returns Dict but missing Lag calculation
ProposeKnownPeers() raft.go:2080-2089 MISSING No peer state broadcast
UpdateKnownPeers() raft.go:2092-2096 MISSING No peer state update
ProposeAddPeer() raft.go:962-983 PARTIAL src/NATS.Server/Raft/RaftNode.cs:372 ProposeAddPeerAsync exists but synchronous replication, no forwarding to leader
ProposeRemovePeer() raft.go:986-1019 PARTIAL src/NATS.Server/Raft/RaftNode.cs:415 ProposeRemovePeerAsync exists but no forwarding, no self-removal handling
MembershipChangeInProgress() raft.go:1021-1025 PORTED src/NATS.Server/Raft/RaftNode.cs:67 MembershipChangeInProgress property
AdjustClusterSize() raft.go:1059-1079 PORTED src/NATS.Server/Raft/RaftNode.cs:790 Added leader-gated cluster-size adjustment with Go floor behavior (min 2)
AdjustBootClusterSize() raft.go:1038-1055 PORTED src/NATS.Server/Raft/RaftNode.cs:781 Added boot-time cluster-size adjustment gated on no current/previous leader
ClusterSize() raft.go:1029-1033 PORTED src/NATS.Server/Raft/RaftNode.cs:778 Added explicit ClusterSize() accessor
ApplyQ() raft.go:2106 PARTIAL src/NATS.Server/Raft/RaftNode.cs:53 CommitQueue exists as Channel-based queue, different API than ipQueue
PauseApply() raft.go:1084-1092 MISSING No apply pausing
ResumeApply() raft.go:1111-1156 MISSING No apply resuming with replay
DrainAndReplaySnapshot() raft.go:1162-1177 PARTIAL src/NATS.Server/Raft/RaftNode.cs:537 DrainAndReplaySnapshotAsync exists but simplified — no catchup cancellation, no commit preservation
LeadChangeC() raft.go:2110 MISSING No leader change channel
QuitC() raft.go:2113 MISSING No quit channel
Created() raft.go:2115-2118 PORTED src/NATS.Server/Raft/RaftNode.cs:43 Added CreatedUtc timestamp captured at node construction and exposed for runtime introspection
Stop() raft.go:2120-2122 PORTED src/NATS.Server/Raft/RaftNode.cs:1095 Added Stop() lifecycle API that transitions to follower, clears leader markers, and signals stop waiters
WaitForStop() raft.go:2124-2128 PORTED src/NATS.Server/Raft/RaftNode.cs:1104 Added synchronous WaitForStop() backed by stop completion signal
Delete() raft.go:2130-2143 PORTED src/NATS.Server/Raft/RaftNode.cs:1109 Added Delete() lifecycle API that stops node, marks deleted, and removes persisted raft directory when configured
IsDeleted() raft.go:2145-2149 PORTED src/NATS.Server/Raft/RaftNode.cs:69 Added IsDeleted state accessor
RecreateInternalSubs() raft.go:658-747 MISSING No NATS internal subscription management
IsSystemAccount() raft.go:648-649 NOT_APPLICABLE .NET does not have system account NRG routing
GetTrafficAccountName() raft.go:652-656 NOT_APPLICABLE .NET does not have account NRG routing

golang/nats-server/server/raft.go — Core State Machine (unexported but critical)

Go Symbol Go File:Line Status .NET Equivalent Notes
raft (struct) raft.go:151-251 PARTIAL src/NATS.Server/Raft/RaftNode.cs:3 RaftNode has basic fields (term, vote, log, peers, commit) but missing: WAL, catchup state, progress map, pae cache, ipQueues, removed peers, many flags
run() raft.go:2275-2362 MISSING No main run loop / state machine goroutine
runAsFollower() raft.go:2441-2496 MISSING No follower state machine with select on channels
runAsCandidate() raft.go:3587-3670 MISSING No candidate state machine with vote collection
runAsLeader() raft.go:2951-3067 MISSING No leader state machine with heartbeat ticker and proposal batching
processAppendEntry() raft.go:3857-4248 MISSING Complex append entry processing with catchup, WAL alignment, truncation — not ported
processAppendEntryResponse() raft.go:4287-4339 MISSING No response processing with catchup triggering
processVoteRequest() raft.go:4780-4845 PARTIAL src/NATS.Server/Raft/RaftNode.cs:142 GrantVote handles basic vote logic but missing: log up-to-dateness check (lastTerm/lastIndex), catchup cancellation, campaign timeout reset
requestVote() raft.go:4856-4872 MISSING No vote request broadcast via RPC
handleAppendEntry() raft.go:3672-3684 MISSING No wire callback for append entries
handleAppendEntryResponse() raft.go:4342-4346 MISSING No wire callback for AE responses
handleVoteRequest() raft.go:4847-4854 MISSING No wire callback for vote requests
handleVoteResponse() raft.go:4764-4778 MISSING No wire callback for vote responses
handleForwardedProposal() raft.go:2854-2874 MISSING No forwarded proposal handler
handleForwardedRemovePeerProposal() raft.go:2820-2851 MISSING No forwarded remove-peer handler

golang/nats-server/server/raft.go — WAL & Storage

Go Symbol Go File:Line Status .NET Equivalent Notes
storeToWAL() raft.go:4360-4396 PARTIAL src/NATS.Server/Raft/RaftWal.cs:74 RaftWal.AppendAsync exists but different storage model (custom binary vs Go's filestore/memstore)
loadEntry() raft.go:3339-3346 MISSING No entry loading from WAL by index
loadFirstEntry() raft.go:3126-3130 MISSING No first-entry loading
truncateWAL() raft.go:3758-3815 MISSING No WAL truncation with snapshot invalidation
resetWAL() raft.go:3819-3821 MISSING No WAL reset
cachePendingEntry() raft.go:4449-4460 MISSING No pending append entry cache

golang/nats-server/server/raft.go — Snapshots

Go Symbol Go File:Line Status .NET Equivalent Notes
snapshot (struct) raft.go:1243-1248 PARTIAL src/NATS.Server/Raft/RaftSnapshot.cs:3 RaftSnapshot has LastIncludedIndex/Term/Data but missing peerstate encoding
encodeSnapshot() raft.go:1254-1279 MISSING No binary snapshot encoding with highwayhash
loadLastSnapshot() raft.go:1660-1707 MISSING No binary snapshot loading with hash verification
setupLastSnapshot() raft.go:1578-1656 MISSING No startup snapshot recovery from disk
installSnapshot() raft.go:1315-1350 PARTIAL src/NATS.Server/Raft/RaftNode.cs:699 InstallSnapshotAsync simplified — no WAL compact, no snapshot file management
termAndIndexFromSnapFile() raft.go:1564-1573 MISSING No snapshot filename parsing

golang/nats-server/server/raft.go — Peer & Membership State

Go Symbol Go File:Line Status .NET Equivalent Notes
peerState (struct) raft.go:4470-4474 MISSING No peer state struct with knownPeers/clusterSize/domainExt
encodePeerState() raft.go:4480-4492 MISSING No binary peer state encoding
decodePeerState() raft.go:4494-4514 MISSING No binary peer state decoding
writePeerState() raft.go:4603-4609 MISSING No peer state file persistence
readPeerState() raft.go:4611-4620 MISSING No peer state file reading
processPeerState() raft.go:4264-4282 MISSING No peer state processing from leader
addPeer() raft.go:2879-2898 PARTIAL src/NATS.Server/Raft/RaftNode.cs:129 AddMember exists but no cluster size/quorum adjustment, no removed-list reversal
removePeer() raft.go:2903-2913 PARTIAL src/NATS.Server/Raft/RaftNode.cs:131 RemoveMember exists but no removed tracking, no cluster size/quorum adjustment
adjustClusterSizeAndQuorum() raft.go:3534-3556 MISSING No dynamic cluster size/quorum recalculation
trackPeer() raft.go:3559-3585 MISSING No automatic peer tracking with add-on-discovery

golang/nats-server/server/raft.go — Elections & Voting

Go Symbol Go File:Line Status .NET Equivalent Notes
switchToFollower() raft.go:4958-4983 PARTIAL src/NATS.Server/Raft/RaftNode.cs:706 RequestStepDown sets Follower but missing: aflr reset, leaderState/leaderSince clear, acks reset, leader update
switchToCandidate() raft.go:4985-5014 PARTIAL src/NATS.Server/Raft/RaftNode.cs:133 StartElection increments term and votes but missing: observer/paused/processed checks, quorum loss signaling
switchToLeader() raft.go:5016-5037 PARTIAL src/NATS.Server/Raft/RaftNode.cs:986 TryBecomeLeader sets Role but missing: aflr setup, peer state broadcast, leader update
campaign() raft.go:2002-2009 PARTIAL src/NATS.Server/Raft/RaftNode.cs:971 CampaignWithPreVote starts election but no random timeout
wonElection() raft.go:4886-4888 PORTED src/NATS.Server/Raft/RaftNode.cs:986 Quorum check in TryBecomeLeader
selectNextLeader() raft.go:1887-1897 MISSING No next-leader selection by highest index
resetElectionTimeout() raft.go:2241-2243 PORTED src/NATS.Server/Raft/RaftNode.cs:737 ResetElectionTimeout with Timer
randElectionTimeout() raft.go:2235-2238 PORTED src/NATS.Server/Raft/RaftNode.cs:727 RandomizedElectionTimeout
randCampaignTimeout() raft.go:1995-1998 PORTED src/NATS.Server/Raft/RaftNode.cs:822 Added RandomizedCampaignTimeout() using Go-equivalent 100-800ms jitter window

golang/nats-server/server/raft.go — Wire Format & RPC

Go Symbol Go File:Line Status .NET Equivalent Notes
voteRequest (struct) raft.go:4549-4556 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:84 RaftVoteRequestWire with Encode/Decode
voteResponse (struct) raft.go:4730-4735 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:132 RaftVoteResponseWire with Encode/Decode
appendEntry (struct) raft.go:2557-2569 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:189 RaftAppendEntryWire with Encode/Decode
appendEntryResponse (struct) raft.go:2760-2766 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:318 RaftAppendEntryResponseWire with Encode/Decode
ae.encode() raft.go:2662-2711 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:202 RaftAppendEntryWire.Encode()
decodeAppendEntry() raft.go:2714-2746 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:255 RaftAppendEntryWire.Decode()
vr.encode() (voteRequest) raft.go:4560-4568 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:94 RaftVoteRequestWire.Encode()
decodeVoteRequest() raft.go:4571-4583 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:109 RaftVoteRequestWire.Decode()
vr.encode() (voteResponse) raft.go:4739-4751 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:142 RaftVoteResponseWire.Encode()
decodeVoteResponse() raft.go:4753-4762 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:159 RaftVoteResponseWire.Decode()
ar.encode() raft.go:2777-2794 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:328 RaftAppendEntryResponseWire.Encode()
decodeAppendEntryResponse() raft.go:2799-2817 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:343 RaftAppendEntryResponseWire.Decode()
idLen constant raft.go:2756 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:23 RaftWireConstants.IdLen = 8
RaftWireHelpers (WriteId/ReadId) raft.go:2693,4581 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:561 RaftWireHelpers class
RaftWireHelpers (uvarint) raft.go:2682,2740 PORTED src/NATS.Server/Raft/RaftWireFormat.cs:597 WriteUvarint/ReadUvarint

golang/nats-server/server/raft.go — NATS Subjects & Transport

Go Symbol Go File:Line Status .NET Equivalent Notes
raftAllSubj constant raft.go:2162 PORTED src/NATS.Server/Raft/RaftSubjects.cs:16 RaftSubjects.All
raftVoteSubj constant raft.go:2163 PORTED src/NATS.Server/Raft/RaftSubjects.cs:22 RaftSubjects.Vote()
raftAppendSubj constant raft.go:2164 PORTED src/NATS.Server/Raft/RaftSubjects.cs:28 RaftSubjects.AppendEntry()
raftPropSubj constant raft.go:2165 PORTED src/NATS.Server/Raft/RaftSubjects.cs:34 RaftSubjects.Proposal()
raftRemovePeerSubj constant raft.go:2166 PORTED src/NATS.Server/Raft/RaftSubjects.cs:40 RaftSubjects.RemovePeer()
raftReply constant raft.go:2167 PORTED src/NATS.Server/Raft/RaftSubjects.cs:46 RaftSubjects.Reply()
raftCatchupReply constant raft.go:2168 PORTED src/NATS.Server/Raft/RaftSubjects.cs:52 RaftSubjects.CatchupReply()
sendRPC() raft.go:4874-4878 PARTIAL src/NATS.Server/Raft/NatsRaftTransport.cs:29 NatsRaftTransport._publish delegate, but no sendq integration
sendReply() raft.go:4880-4884 MISSING No reply sending via sendq
sendHeartbeat() raft.go:4545-4547 PARTIAL src/NATS.Server/Raft/NatsRaftTransport.cs:229 SendHeartbeatAsync exists but optimistic (no real ACK tracking)
IRaftTransport PORTED src/NATS.Server/Raft/RaftTransport.cs:3 Interface with AppendEntries, RequestVote, InstallSnapshot, SendTimeoutNow, SendHeartbeat
InMemoryRaftTransport PORTED src/NATS.Server/Raft/RaftTransport.cs:26 Full in-memory transport for testing
NatsRaftTransport PORTED src/NATS.Server/Raft/NatsRaftTransport.cs:18 Wire-level NATS transport with binary encoding
createInternalSubs() raft.go:2209-2233 MISSING No internal NATS subscription creation
subscribe() / unsubscribe() raft.go:2194-2206 MISSING No internal subscription management

golang/nats-server/server/raft.go — Catchup & Leader Coordination

Go Symbol Go File:Line Status .NET Equivalent Notes
catchupState (struct) raft.go:260-268 MISSING No catchup state tracking
runCatchup() raft.go:3132-3236 MISSING No catchup goroutine for lagging followers
catchupFollower() raft.go:3266-3337 MISSING No follower catchup initiation
createCatchup() raft.go:3718-3735 MISSING No catchup subscription/inbox creation
cancelCatchup() raft.go:3689-3697 MISSING No catchup cancellation
catchupStalled() raft.go:3702-3712 MISSING No stall detection
sendSnapshotToFollower() raft.go:3239-3264 MISSING No snapshot streaming to follower
sendCatchupSignal() raft.go:3738-3745 MISSING No catchup signal to upper layer
cancelCatchupSignal() raft.go:3748-3754 MISSING No catchup signal cancellation

golang/nats-server/server/raft.go — Commit & Apply

Go Symbol Go File:Line Status .NET Equivalent Notes
applyCommit() raft.go:3350-3462 MISSING Complex commit application with entry type dispatch, peer state processing, membership changes
tryCommit() raft.go:3468-3487 MISSING No quorum-based commit with ack counting
trackResponse() raft.go:3493-3529 MISSING No response tracking with ack map
sendMembershipChange() raft.go:2918-2949 MISSING No membership change send with WAL store

golang/nats-server/server/raft.go — Persistence & Term/Vote

Go Symbol Go File:Line Status .NET Equivalent Notes
writeTermVote() raft.go:4708-4727 PARTIAL src/NATS.Server/Raft/RaftNode.cs:993 PersistAsync writes meta.json (JSON) but Go uses binary tav.idx with dedup
readTermVote() raft.go:4637-4656 PARTIAL src/NATS.Server/Raft/RaftNode.cs:1013 LoadPersistedStateAsync reads meta.json but Go uses binary tav.idx
writePeerState() (on raft) raft.go:4589-4600 MISSING No binary peer state file writing
setWriteErr() / setWriteErrLocked() raft.go:4659-4704 MISSING No write error tracking with permission/space error escalation

golang/nats-server/server/raft.go — Server Integration

Go Symbol Go File:Line Status .NET Equivalent Notes
bootstrapRaftNode() raft.go:346-407 MISSING No raft bootstrap with peer validation and directory setup
initRaftNode() raft.go:410-614 MISSING No full raft initialization with WAL replay, snapshot recovery, peer state restore
startRaftNode() raft.go:617-628 MISSING No start-and-run goroutine
registerRaftNode() raft.go:776-783 MISSING No server-level raft registration
unregisterRaftNode() raft.go:786-792 MISSING No server-level raft unregistration
lookupRaftNode() raft.go:803-811 MISSING No raft node lookup by group
numRaftNodes() raft.go:795-799 MISSING No raft node count
stepdownRaftNodes() raft.go:831-851 MISSING No server-wide raft stepdown
shutdownRaftNodes() raft.go:856-875 MISSING No server-wide raft shutdown
transferRaftLeaders() raft.go:880-903 MISSING No server-wide leader transfer
reloadDebugRaftNodes() raft.go:815-827 NOT_APPLICABLE Debug flag reload is Go-specific
serverNameForNode() raft.go:759-763 NOT_APPLICABLE Server-level node mapping not yet needed
clusterNameForNode() raft.go:767-772 NOT_APPLICABLE Cluster-level node mapping not yet needed

golang/nats-server/server/raft.go — .NET Extensions (not in Go)

Go Symbol Go File:Line Status .NET Equivalent Notes
(none — .NET addition) PORTED src/NATS.Server/Raft/RaftWireFormat.cs:366 RaftPreVoteRequestWire — pre-vote wire format (Go does not have pre-vote)
(none — .NET addition) PORTED src/NATS.Server/Raft/RaftWireFormat.cs:410 RaftPreVoteResponseWire — pre-vote wire format
(none — .NET addition) PORTED src/NATS.Server/Raft/RaftWireFormat.cs:455 RaftTimeoutNowWire — leadership transfer wire format
(none — .NET addition) PORTED src/NATS.Server/Raft/RaftWireFormat.cs:508 RaftInstallSnapshotChunkWire — chunked snapshot wire format
(none — .NET addition) PORTED src/NATS.Server/Raft/CompactionPolicy.cs:9 CompactionPolicy / CompactionOptions — configurable log compaction
(none — .NET addition) PORTED src/NATS.Server/Raft/SnapshotChunkEnumerator.cs:16 SnapshotChunkEnumerator — snapshot chunking
(none — .NET addition) PORTED src/NATS.Server/Raft/RaftNode.cs:251 ReadIndexAsync — linearizable reads (Go does not expose this)
(none — .NET addition) PORTED src/NATS.Server/Raft/RaftNode.cs:464 Joint consensus (BeginJointConsensus/CommitJointConsensus)
(none — .NET addition) PORTED src/NATS.Server/Raft/RaftNode.cs:790 TransferLeadershipAsync with TimeoutNow RPC
(none — .NET addition) PORTED src/NATS.Server/Raft/RaftNode.cs:906 Pre-vote protocol (StartPreVote/RequestPreVote)

golang/nats-server/server/raft.go — Object Pools & Helpers

Go Symbol Go File:Line Status .NET Equivalent Notes
cePool / newCommittedEntry / ReturnToPool raft.go:2498-2532 NOT_APPLICABLE Go sync.Pool for CommittedEntry; .NET uses GC
entryPool / newEntry raft.go:2534-2547 NOT_APPLICABLE Go sync.Pool for Entry; .NET uses GC
aePool / newAppendEntry / returnToPool raft.go:2549-2583 NOT_APPLICABLE Go sync.Pool for appendEntry; .NET uses GC
pePool / newProposedEntry raft.go:2586-2603 NOT_APPLICABLE Go sync.Pool for proposedEntry; .NET uses GC
arPool / newAppendEntryResponse raft.go:2748-2775 NOT_APPLICABLE Go sync.Pool for appendEntryResponse; .NET uses GC
peers sync.Map (string interning) raft.go:2797 NOT_APPLICABLE Go-specific string interning optimization
debug() / warn() / error() raft.go:2364-2379 NOT_APPLICABLE Logging helpers — .NET uses ILogger
dios semaphore raft.go:1665-1667 NOT_APPLICABLE Go disk I/O semaphore — .NET uses async I/O
ipQueue usage raft.go:233-238 MISSING Go uses typed ipQueue channels for proposals, entries, votes, responses — .NET has no equivalent internal queue infrastructure

golang/nats-server/server/raft.go — Constants & Configuration

Go Symbol Go File:Line Status .NET Equivalent Notes
Election timeout defaults raft.go:277-287 PARTIAL src/NATS.Server/Raft/RaftNode.cs:56-57 .NET uses 150-300ms defaults; Go uses 4-9s defaults. Different design choice
hbInterval raft.go:283 PORTED src/NATS.Server/Raft/RaftNode.cs:10 Added HbIntervalDefault = 1s constant
lostQuorumInterval raft.go:284 PORTED src/NATS.Server/Raft/RaftNode.cs:11 Added LostQuorumIntervalDefault = 10s constant
observerModeInterval raft.go:286 PORTED src/NATS.Server/Raft/RaftNode.cs:12 Added ObserverModeIntervalDefault = 48h constant
peerRemoveTimeout raft.go:287 PORTED src/NATS.Server/Raft/RaftNode.cs:13 Added PeerRemoveTimeoutDefault = 5m constant
Error sentinels raft.go:319-343 PARTIAL .NET uses InvalidOperationException instead of typed error sentinels
noLeader / noVote constants raft.go:4954-4956 PORTED src/NATS.Server/Raft/RaftNode.cs:5 Added explicit NoLeader / NoVote empty-string constants
paeDropThreshold / paeWarnThreshold raft.go:4399-4401 MISSING No pending append entry limits
maxBatch / maxEntries raft.go:3004-3005 MISSING No proposal batching thresholds
extensionState raft.go:4462-4468 MISSING No domain extension state tracking

Keeping This File Updated

After porting work is completed:

  1. Update status: Change MISSING → PORTED or PARTIAL → PORTED for each item completed
  2. Add .NET path: Fill in the ".NET Equivalent" column with the actual file:line
  3. Re-count LOC: Update the LOC numbers in stillmissing.md:
    # Re-count .NET source LOC for this module
    find src/NATS.Server/Raft/ -name '*.cs' -type f -exec cat {} + | wc -l
    # Re-count .NET test LOC for this module
    find tests/NATS.Server.Tests/Raft/ -name '*.cs' -type f -exec cat {} + | wc -l
    
  4. Add a changelog entry below with date and summary of what was ported
  5. Update the parity DB if new test mappings were created:
    sqlite3 docs/test_parity.db "INSERT INTO test_mappings (go_test_id, dotnet_test_id, confidence, notes) VALUES (?, ?, 'manual', 'ported in YYYY-MM-DD session')"
    

Change Log

Date Change By
2026-02-25 File created with LLM analysis instructions auto
2026-02-25 Full gap analysis completed: 196 items inventoried across 12 categories. Summary: 46 PORTED, 38 PARTIAL, 99 MISSING, 13 NOT_APPLICABLE, 0 DEFERRED. Wire format is well-ported; core state machine (run loop, catchup, WAL integration) is largely missing. claude-opus
2026-02-25 Ported RAFT API/lifecycle parity batch: LeaderSince/GroupLeader/Leaderless/HadPreviousLeader, observer toggles, Progress/Size/Applied, cluster-size adjustors, stop/delete APIs, campaign timeout jitter, and core timing/leader constants with targeted tests in RaftNodeParityBatch2Tests. codex
2026-02-26 Ported RAFT parity batch: added ProposeMultiAsync, peer parity fields (Lag, Current) + refresh helpers, explicit CommittedEntry payload type, and general RaftEntry model/wire conversion helpers with focused tests in RaftParityBatch3Tests. codex