- 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
27 KiB
Protocol — Gap Analysis
This file tracks what has and hasn't been ported from Go to .NET for the Protocol 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:
- Extract all exported types (structs, interfaces, type aliases)
- Extract all exported methods on those types (receiver functions)
- Extract all exported standalone functions
- Note key constants, enums, and protocol states
- Note important unexported helpers that implement core logic (functions >20 lines)
- 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:
- Search for a matching type, method, or function in .NET
- If found, compare the behavior: does it handle the same edge cases? Same error paths?
- If partially implemented, note what's missing
- If not found, note it as MISSING
Step 3: Cross-Reference Tests
Compare Go test functions against .NET test methods:
- For each Go
Test*function, check if a corresponding .NET[Fact]or[Theory]exists - Note which test scenarios are covered and which are missing
- 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 Protocol
- The parser is a byte-by-byte state machine. In .NET, use
System.IO.Pipelinesfor zero-copy parsing withReadOnlySequence<byte>. - Control line limit: 4096 bytes. Default max payload: 1MB.
- Extended protocol:
HPUB/HMSG(headers),RPUB/RMSG(routes) — check if these are implemented. - Fuzz tests in Go may map to
[Theory]tests with randomized inputs in .NET.
Go Reference Files (Source)
golang/nats-server/server/parser.go— Protocol state machine (PUB, SUB, UNSUB, CONNECT, INFO, PING/PONG, HPUB/HMSG, RPUB/RMSG)golang/nats-server/server/proto.go— Wire-level protocol writing (sendProto, sendInfo, etc.)golang/nats-server/server/const.go— Protocol constants, limits (control line 4096, default max payload 1MB)
Go Reference Files (Tests)
golang/nats-server/server/parser_test.gogolang/nats-server/server/parser_fuzz_test.gogolang/nats-server/server/server_fuzz_test.gogolang/nats-server/server/subject_fuzz_test.gogolang/nats-server/server/split_test.go
.NET Implementation Files (Source)
src/NATS.Server/Protocol/NatsParser.cs— State machinesrc/NATS.Server/Protocol/NatsProtocol.cs— Wire-level writingsrc/NATS.Server/Protocol/NatsHeaderParser.cssrc/NATS.Server/Protocol/ClientCommandMatrix.cssrc/NATS.Server/Protocol/MessageTraceContext.cssrc/NATS.Server/Protocol/ProxyProtocol.cs
.NET Implementation Files (Tests)
tests/NATS.Server.Tests/Protocol/
Gap Inventory
golang/nats-server/server/parser.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
parserState (type) |
parser.go:24 | PORTED | src/NATS.Server/Protocol/NatsParser.cs |
Go uses an iota int type; .NET uses enum CommandType + internal awaiting-payload state |
parseState (struct) |
parser.go:25 | PARTIAL | src/NATS.Server/Protocol/NatsParser.cs:37 |
.NET NatsParser carries equivalent per-command state via fields (_awaitingPayload, _expectedPayloadSize, etc.). Missing: argBuf/msgBuf split-buffer accumulation fields, scratch fixed-size buffer, header lazy-parse field. The .NET parser relies on System.IO.Pipelines buffering rather than explicit accumulator fields. |
pubArg (struct) |
parser.go:37 | PARTIAL | src/NATS.Server/Protocol/NatsParser.cs:21 |
ParsedCommand covers subject, reply, size, hdr. Missing: origin, account, pacache, mapped, queues, szb, hdb, psi, trace, delivered — clustering/routing/JetStream fields not yet needed for core client protocol. |
OP_START … INFO_ARG (parser state constants) |
parser.go:57–134 | PARTIAL | src/NATS.Server/Protocol/NatsParser.cs:104 |
All CLIENT-facing states implemented (PUB, HPUB, SUB, UNSUB, CONNECT, INFO, PING, PONG, +OK, -ERR). MISSING states: OP_A/ASUB_ARG/AUSUB_ARG (A+/A- for gateways), OP_R/OP_RS/OP_L/OP_LS (RMSG/LMSG/RS+/RS-/LS+/LS-), OP_M/MSG_ARG/HMSG_ARG (routing MSG/HMSG). See ClientCommandMatrix.cs for partial routing opcode routing. |
client.parse() |
parser.go:136 | PARTIAL | src/NATS.Server/Protocol/NatsParser.cs:69 |
Core CLIENT-facing parse loop ported as NatsParser.TryParse() using ReadOnlySequence<byte> + SequenceReader. Missing: byte-by-byte incremental state transitions (Go uses byte-by-byte state machine; .NET scans for \r\n on each call), auth-set check before non-CONNECT op, MQTT dispatch (c.mqttParse), gateway in-CONNECT gating, ROUTER/GATEWAY/LEAF protocol dispatch (RMSG, LMSG, RS+, RS-, A+, A-). |
protoSnippet() |
parser.go:1236 | PORTED | src/NATS.Server/Protocol/NatsParser.cs:206 |
Added Go-style quoted snippet helper (ProtoSnippet(start,max,buffer)) and default overload, with parity tests in tests/NATS.Server.Tests/Protocol/ProtocolParserSnippetGapParityTests.cs. |
client.overMaxControlLineLimit() |
parser.go:1251 | PARTIAL | src/NATS.Server/Protocol/NatsParser.cs:83 |
.NET now emits structured max-control-line errors with snippet context (snip=...). Missing: kind-check (Go only enforces for CLIENT) and explicit connection-close side effect (closeConnection(MaxControlLineExceeded)) at parser layer. |
client.clonePubArg() |
parser.go:1267 | MISSING | — | Split-buffer scenario: clones pubArg and re-processes when payload spans two reads. Not needed in .NET because System.IO.Pipelines handles buffering, but there is no explicit equivalent. |
parseState.getHeader() |
parser.go:1297 | PARTIAL | src/NATS.Server/Protocol/NatsHeaderParser.cs:25 |
Go lazily parses http.Header from the raw message buffer. .NET has NatsHeaderParser.Parse() which parses NATS/1.0 headers. Missing: lazy evaluation on the parsed command (header is not cached on ParsedCommand). |
golang/nats-server/server/proto.go
Note: This Go file (proto.go) implements a protobuf wire-format scanner/encoder (field tags, varints, length-delimited bytes) used internally for NATS's binary internal protocol (e.g. JetStream metadata encoding). It is unrelated to the NATS text protocol.
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
errProtoInsufficient |
proto.go:24 | PORTED | src/NATS.Server/Protocol/ProtoWire.cs:5 |
Added sentinel-equivalent error constant and ProtoWireException usage for insufficient varint/bytes payloads. |
errProtoOverflow |
proto.go:25 | PORTED | src/NATS.Server/Protocol/ProtoWire.cs:6 |
Added overflow sentinel-equivalent error constant for invalid 10-byte varint tails. |
errProtoInvalidFieldNumber |
proto.go:26 | PORTED | src/NATS.Server/Protocol/ProtoWire.cs:7 |
Added invalid field-number sentinel-equivalent error constant used by tag scanning. |
protoScanField() |
proto.go:28 | PORTED | src/NATS.Server/Protocol/ProtoWire.cs:9 |
Added field scanner that composes tag + value scanning and returns total consumed size. |
protoScanTag() |
proto.go:42 | PORTED | src/NATS.Server/Protocol/ProtoWire.cs:16 |
Added tag scanner with Go-equivalent field number validation (1..int32). |
protoScanFieldValue() |
proto.go:61 | PORTED | src/NATS.Server/Protocol/ProtoWire.cs:26 |
Added wire-type scanner for varint/fixed32/fixed64/length-delimited forms. |
protoScanVarint() |
proto.go:77 | PORTED | src/NATS.Server/Protocol/ProtoWire.cs:38 |
Added 10-byte max varint scanner with insufficient/overflow parity errors. |
protoScanBytes() |
proto.go:179 | PORTED | src/NATS.Server/Protocol/ProtoWire.cs:65 |
Added length-delimited scanner that validates the declared size against remaining payload bytes. |
protoEncodeVarint() |
proto.go:190 | PORTED | src/NATS.Server/Protocol/ProtoWire.cs:74 |
Added varint encoder and round-trip coverage in parity tests. |
golang/nats-server/server/const.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
Command (type) |
const.go:23 | NOT_APPLICABLE | — | Go string type alias for signal commands (stop/quit/reload). Managed by OS signal handling; not applicable to .NET server lifecycle which uses CancellationToken. |
CommandStop, CommandQuit, CommandReopen, CommandReload |
const.go:27–34 | NOT_APPLICABLE | — | OS signal-based server control commands. .NET uses CancellationToken + IHostedService lifecycle. |
gitCommit, serverVersion (build vars) |
const.go:39 | NOT_APPLICABLE | — | Go linker-injected build vars. Equivalent handled by .NET assembly info / AssemblyInformationalVersionAttribute. |
formatRevision() |
const.go:47 | NOT_APPLICABLE | — | Formats a 7-char VCS commit hash for display. Go-specific build info pattern; not needed in .NET. |
init() (build info) |
const.go:54 | NOT_APPLICABLE | — | Reads debug.BuildInfo at startup to extract VCS revision. Not applicable to .NET. |
VERSION = "2.14.0-dev" |
const.go:69 | PARTIAL | src/NATS.Server/Protocol/NatsProtocol.cs:11 |
.NET has Version = "0.1.0". The version string is present but does not match Go's version. |
PROTO = 1 |
const.go:76 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:12 |
ProtoVersion = 1 |
DEFAULT_PORT = 4222 |
const.go:79 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:10 |
DefaultPort = 4222 |
RANDOM_PORT = -1 |
const.go:83 | NOT_APPLICABLE | — | Used in Go test helpers to request a random port. .NET tests use GetFreePort() pattern. |
DEFAULT_HOST = "0.0.0.0" |
const.go:86 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:11 |
Added NatsProtocol.DefaultHost and wired NatsOptions.Host default to it. |
MAX_CONTROL_LINE_SIZE = 4096 |
const.go:91 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:7 |
MaxControlLineSize = 4096 |
MAX_PAYLOAD_SIZE = 1MB |
const.go:95 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:8 |
MaxPayloadSize = 1024 * 1024 |
MAX_PAYLOAD_MAX_SIZE = 8MB |
const.go:99 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:9 |
Added NatsProtocol.MaxPayloadMaxSize (8MB threshold constant). |
MAX_PENDING_SIZE = 64MB |
const.go:103 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:9 |
MaxPendingSize = 64 * 1024 * 1024 |
DEFAULT_MAX_CONNECTIONS = 64K |
const.go:106 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:13 |
Added NatsProtocol.DefaultMaxConnections and wired NatsOptions.MaxConnections. |
TLS_TIMEOUT = 2s |
const.go:109 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:18, src/NATS.Server/NatsOptions.cs:102 |
Added protocol default and wired TLS timeout default in options. |
DEFAULT_TLS_HANDSHAKE_FIRST_FALLBACK_DELAY = 50ms |
const.go:114 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:19, src/NATS.Server/NatsOptions.cs:104 |
Added protocol default and wired TlsHandshakeFirstFallback default in options. |
AUTH_TIMEOUT = 2s |
const.go:118 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:20, src/NATS.Server/NatsOptions.cs:49 |
Added protocol default and wired AuthTimeout default in options. |
DEFAULT_PING_INTERVAL = 2min |
const.go:122 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:21, src/NATS.Server/NatsOptions.cs:19 |
Added protocol default and wired PingInterval default in options. |
DEFAULT_PING_MAX_OUT = 2 |
const.go:125 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:14, src/NATS.Server/NatsOptions.cs:20 |
Added protocol default and wired MaxPingsOut default in options. |
CR_LF = "\r\n" |
const.go:128 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:15 |
CrLf byte array. |
LEN_CR_LF = 2 |
const.go:131 | PORTED | Implicit in .NET (+ 2 literals in parser). |
Used as literal 2 in TryReadPayload. |
DEFAULT_FLUSH_DEADLINE = 10s |
const.go:134 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:22, src/NATS.Server/NatsOptions.cs:18 |
Added protocol default and wired WriteDeadline default in options. |
DEFAULT_HTTP_PORT = 8222 |
const.go:137 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:15 |
Added NatsProtocol.DefaultHttpPort constant and parity assertions in protocol constants tests. |
DEFAULT_HTTP_BASE_PATH = "/" |
const.go:140 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:16 |
Added NatsProtocol.DefaultHttpBasePath constant and parity assertions in protocol constants tests. |
ACCEPT_MIN_SLEEP = 10ms |
const.go:143 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:23, src/NATS.Server/NatsServer.cs:94 |
Added protocol default and wired accept-loop backoff minimum in server. |
ACCEPT_MAX_SLEEP = 1s |
const.go:146 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:24, src/NATS.Server/NatsServer.cs:95 |
Added protocol default and wired accept-loop backoff maximum in server. |
DEFAULT_ROUTE_CONNECT = 1s |
const.go:149 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:31 |
Added NatsProtocol.DefaultRouteConnect constant. |
DEFAULT_ROUTE_CONNECT_MAX = 30s |
const.go:152 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:32 |
Added NatsProtocol.DefaultRouteConnectMax constant. |
DEFAULT_ROUTE_RECONNECT = 1s |
const.go:155 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:33 |
Added NatsProtocol.DefaultRouteReconnect constant. |
DEFAULT_ROUTE_DIAL = 1s |
const.go:158 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:34 |
Added NatsProtocol.DefaultRouteDial constant. |
DEFAULT_ROUTE_POOL_SIZE = 3 |
const.go:161 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:17 |
Added NatsProtocol.DefaultRoutePoolSize constant. |
DEFAULT_LEAF_NODE_RECONNECT = 1s |
const.go:164 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:35 |
Added NatsProtocol.DefaultLeafNodeReconnect constant. |
DEFAULT_LEAF_TLS_TIMEOUT = 2s |
const.go:167 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:36 |
Added NatsProtocol.DefaultLeafTlsTimeout constant. |
PROTO_SNIPPET_SIZE = 32 |
const.go:170 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:9, src/NATS.Server/Protocol/NatsParser.cs:222 |
Added snippet-size constant and wired parser default ProtoSnippet overload to it. |
MAX_CONTROL_LINE_SNIPPET_SIZE = 128 |
const.go:172 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:8, src/NATS.Server/Protocol/NatsParser.cs:85 |
Added max control-line snippet size constant and wired control-line violation errors to use it. |
MAX_MSG_ARGS = 4 |
const.go:175 | NOT_APPLICABLE | — | Used in Go's manual arg-split loop. .NET uses SplitArgs() with stack-allocated ranges. |
MAX_RMSG_ARGS = 6 |
const.go:178 | NOT_APPLICABLE | — | Used in RMSG parsing. RMSG not yet ported. |
MAX_HMSG_ARGS = 7 |
const.go:180 | NOT_APPLICABLE | — | Used in HMSG parsing. HMSG routing not yet ported. |
MAX_PUB_ARGS = 3 |
const.go:183 | NOT_APPLICABLE | — | Used in PUB arg splitting. .NET uses dynamic SplitArgs. |
MAX_HPUB_ARGS = 4 |
const.go:186 | NOT_APPLICABLE | — | Used in HPUB arg splitting. .NET uses dynamic SplitArgs. |
MAX_RSUB_ARGS = 6 |
const.go:189 | NOT_APPLICABLE | — | Used in RS+/LS+ subscription arg splitting. Not yet ported. |
DEFAULT_MAX_CLOSED_CLIENTS = 10000 |
const.go:192 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:15, src/NATS.Server/NatsOptions.cs:89 |
Added protocol default and wired closed-client ring size default in options. |
DEFAULT_LAME_DUCK_DURATION = 2min |
const.go:196 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:25, src/NATS.Server/NatsOptions.cs:59 |
Added protocol default and wired lame-duck duration default in options. |
DEFAULT_LAME_DUCK_GRACE_PERIOD = 10s |
const.go:200 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:26, src/NATS.Server/NatsOptions.cs:60 |
Added protocol default and wired lame-duck grace period default in options. |
DEFAULT_LEAFNODE_INFO_WAIT = 1s |
const.go:203 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:37 |
Added NatsProtocol.DefaultLeafNodeInfoWait constant. |
DEFAULT_LEAFNODE_PORT = 7422 |
const.go:206 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:18 |
Added NatsProtocol.DefaultLeafNodePort constant. |
DEFAULT_CONNECT_ERROR_REPORTS = 3600 |
const.go:214 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:16, src/NATS.Server/NatsOptions.cs:86 |
Added protocol default and wired ConnectErrorReports default in options. |
DEFAULT_RECONNECT_ERROR_REPORTS = 1 |
const.go:220 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:17, src/NATS.Server/NatsOptions.cs:87 |
Added protocol default and wired ReconnectErrorReports default in options. |
DEFAULT_RTT_MEASUREMENT_INTERVAL = 1h |
const.go:224 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:38 |
Added NatsProtocol.DefaultRttMeasurementInterval constant. |
DEFAULT_ALLOW_RESPONSE_MAX_MSGS = 1 |
const.go:228 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:24 |
Added NatsProtocol.DefaultAllowResponseMaxMsgs constant. |
DEFAULT_ALLOW_RESPONSE_EXPIRATION = 2min |
const.go:232 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:39 |
Added NatsProtocol.DefaultAllowResponseExpiration constant. |
DEFAULT_SERVICE_EXPORT_RESPONSE_THRESHOLD = 2min |
const.go:237 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:40 |
Added NatsProtocol.DefaultServiceExportResponseThreshold constant. |
DEFAULT_SERVICE_LATENCY_SAMPLING = 100 |
const.go:241 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:25 |
Added NatsProtocol.DefaultServiceLatencySampling constant. |
DEFAULT_SYSTEM_ACCOUNT = "$SYS" |
const.go:244 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:26, src/NATS.Server/Auth/Account.cs:10 |
Added protocol-level constant; existing account model uses the same value ($SYS). |
DEFAULT_GLOBAL_ACCOUNT = "$G" |
const.go:247 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:27 |
Added NatsProtocol.DefaultGlobalAccount constant. |
DEFAULT_ACCOUNT_FETCH_TIMEOUT = 1900ms |
const.go:250 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:41 |
Added NatsProtocol.DefaultAccountFetchTimeout constant. |
.NET-Only Additions (no Go counterpart in the three source files)
| .NET Symbol | .NET File:Line | Status | Notes |
|---|---|---|---|
NatsHeaderParser |
src/NATS.Server/Protocol/NatsHeaderParser.cs:20 |
PORTED | Parses NATS/1.0 header blocks. Go uses http.Header/textproto lazily from getHeader() on parseState. .NET provides an eager standalone parser. |
NatsHeaders (struct) |
src/NATS.Server/Protocol/NatsHeaderParser.cs:6 |
PORTED | Structured result for parsed NATS headers (status, description, key-value map). No direct Go counterpart — Go uses http.Header directly. |
ClientCommandMatrix |
src/NATS.Server/Protocol/ClientCommandMatrix.cs:4 |
PORTED | Encodes which inter-server opcodes (RS+, RS-, RMSG, A+, A-, LS+, LS-, LMSG) are allowed per client kind. Corresponds to the switch c.kind / switch c.op dispatch inside parse(). |
MessageTraceContext |
src/NATS.Server/Protocol/MessageTraceContext.cs:3 |
PORTED | Captures client name/lang/version/headers from CONNECT options for trace logging. Equivalent to fields inside Go's client struct populated during processConnect. |
ProxyProtocolParser |
src/NATS.Server/Protocol/ProxyProtocol.cs:48 |
PORTED | PROXY protocol v1/v2 pure-parser. Corresponds to client_proxyproto.go (not in the three listed source files, but closely related to the protocol module). |
ProxyAddress, ProxyParseResult, ProxyParseResultKind |
src/NATS.Server/Protocol/ProxyProtocol.cs:11 |
PORTED | Supporting types for PROXY protocol parsing. |
ServerInfo (class) |
src/NATS.Server/Protocol/NatsProtocol.cs:39 |
PORTED | Wire-format INFO message JSON model. Corresponds to Go's Info struct in server.go. |
ClientOptions (class) |
src/NATS.Server/Protocol/NatsProtocol.cs:98 |
PARTIAL | Wire-format CONNECT options JSON model. Missing: nkey, sig, jwt fields present but auth handling not implemented server-side. |
Keeping This File Updated
After porting work is completed:
- Update status: Change
MISSING → PORTEDorPARTIAL → PORTEDfor each item completed - Add .NET path: Fill in the ".NET Equivalent" column with the actual file:line
- Re-count LOC: Update the LOC numbers in
stillmissing.md:# Re-count .NET source LOC for this module find src/NATS.Server/Protocol/ -name '*.cs' -type f -exec cat {} + | wc -l # Re-count .NET test LOC for this module find tests/NATS.Server.Tests/Protocol/ -name '*.cs' -type f -exec cat {} + | wc -l - Add a changelog entry below with date and summary of what was ported
- 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')"
Test Cross-Reference Summary
Go test file: parser_test.go
| Go Test | Status | .NET Equivalent |
|---|---|---|
TestParsePing |
PARTIAL | tests/NATS.Server.Tests/ParserTests.cs: Parse_PING — covers full PING\r\n; missing byte-by-byte incremental state assertions |
TestParsePong |
PARTIAL | tests/NATS.Server.Tests/ParserTests.cs: Parse_PONG — covers full PONG\r\n; missing ping.out counter decrement test |
TestParseConnect |
PORTED | tests/NATS.Server.Tests/ParserTests.cs: Parse_CONNECT |
TestParseSub |
PORTED | tests/NATS.Server.Tests/ParserTests.cs: Parse_SUB_without_queue, Parse_SUB_with_queue |
TestParsePub |
PARTIAL | tests/NATS.Server.Tests/ParserTests.cs: Parse_PUB_with_payload, Parse_PUB_with_reply — missing overflow payload error scenario |
TestParsePubSizeOverflow |
PORTED | tests/NATS.Server.Tests/ParserTests.cs: Parse_pub_size_overflow_fails — explicit oversized PUB payload-size argument test now asserts parser rejection (Invalid payload size) |
TestParsePubArg |
PORTED | tests/NATS.Server.Tests/ParserTests.cs: Parse_PUB_argument_variations (Theory) |
TestParsePubBadSize |
PARTIAL | tests/NATS.Server.Tests/ParserTests.cs: Parse_malformed_protocol_fails covers some bad args; missing specific mpay (max payload per-client) test |
TestParseHeaderPub |
PORTED | tests/NATS.Server.Tests/ParserTests.cs: Parse_HPUB |
TestParseHeaderPubArg |
MISSING | No .NET Theory equivalent for the 32 HPUB argument variations with mixed spaces/tabs |
TestParseRoutedHeaderMsg (HMSG) |
MISSING | No .NET equivalent — ROUTER/GATEWAY HMSG parsing not yet ported |
TestParseRouteMsg (RMSG) |
MISSING | No .NET equivalent — ROUTER RMSG parsing not yet ported |
TestParseMsgSpace |
MISSING | No .NET equivalent — MSG opcode for routes not yet ported |
TestShouldFail |
PARTIAL | tests/NATS.Server.Tests/ParserTests.cs: Parse_malformed_protocol_fails — covers subset; documented behavioral differences for byte-by-byte vs prefix-scan parser |
TestProtoSnippet |
PORTED | tests/NATS.Server.Tests/Protocol/ProtocolParserSnippetGapParityTests.cs: ProtoSnippet_* validates Go-style snippet behavior and parser error context wiring. |
TestParseOK |
PORTED | tests/NATS.Server.Tests/ParserTests.cs: Parse_case_insensitive includes +OK (via ParsedCommand.Simple) |
TestMaxControlLine |
PARTIAL | tests/NATS.Server.Tests/ParserTests.cs: Parse_exceeding_max_control_line_fails — covers basic enforcement; missing per-client-kind bypass (LEAF/ROUTER/GATEWAY exempt) |
Go test file: split_test.go
| Go Test | Status | .NET Equivalent |
|---|---|---|
TestSplitBufferSubOp |
PARTIAL | tests/NATS.Server.Tests/ParserTests.cs — System.IO.Pipelines handles split buffers transparently; no explicit split-state test |
TestSplitBufferUnsubOp |
PARTIAL | Same as above |
TestSplitBufferPubOp … TestSplitBufferPubOp5 |
PARTIAL | Parse_PUB_with_payload covers basic case; no multi-chunk split test |
TestSplitConnectArg |
PARTIAL | No explicit argBuf accumulation test |
TestSplitDanglingArgBuf |
NOT_APPLICABLE | .NET parser has no argBuf — pipeline buffering makes this moot |
TestSplitRoutedMsgArg |
MISSING | RMSG not yet ported |
TestSplitBufferMsgOp |
MISSING | RMSG not yet ported |
TestSplitBufferLeafMsgArg |
MISSING | LMSG (leaf) not yet ported |
Go test file: parser_fuzz_test.go
| Go Test | Status | .NET Equivalent |
|---|---|---|
FuzzParser |
MISSING | No .NET fuzz test. Could be approximated with property-based testing ([Theory] with random inputs via FsCheck or Bogus). |
Go test file: server_fuzz_test.go
| Go Test | Status | .NET Equivalent |
|---|---|---|
FuzzServerTLS |
MISSING | TLS-first handshake and TLS fuzzing not yet implemented in .NET server. |
Go test file: subject_fuzz_test.go
| Go Test | Status | .NET Equivalent |
|---|---|---|
FuzzSubjectsCollide |
MISSING | SubjectsCollide() function not yet ported. .NET has SubjectMatch.IsValidSubject() and wildcard matching but not a SubjectsCollide API. |
Change Log
| Date | Change | By |
|---|---|---|
| 2026-02-26 | Added parser overflow parity test (Parse_pub_size_overflow_fails) and reclassified TestParsePubSizeOverflow from MISSING to PORTED. |
codex |
| 2026-02-25 | File created with LLM analysis instructions | auto |
| 2026-02-25 | Full gap inventory populated: parser.go, proto.go, const.go; test cross-reference for all 5 Go test files | claude-sonnet-4-6 |
| 2026-02-25 | Executed protocol defaults parity batch: introduced missing const/default surfaces in NatsProtocol, wired NatsOptions and accept-loop defaults, added targeted tests (ProtocolDefaultConstantsGapParityTests), and reclassified 16 const.go rows from MISSING to PORTED |
codex |
| 2026-02-25 | Executed protocol proto-wire parity batch: added ProtoWire scanners/encoder and parity tests (ProtoWireParityTests), and reclassified all 9 proto.go rows from MISSING to PORTED |
codex |