# Protocol — Gap Analysis > This file tracks what has and hasn't been ported from Go to .NET for the **Protocol** module. > See [stillmissing.md](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: ```bash 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.Pipelines` for zero-copy parsing with `ReadOnlySequence`. - 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.go` - `golang/nats-server/server/parser_fuzz_test.go` - `golang/nats-server/server/server_fuzz_test.go` - `golang/nats-server/server/subject_fuzz_test.go` - `golang/nats-server/server/split_test.go` ## .NET Implementation Files (Source) - `src/NATS.Server/Protocol/NatsParser.cs` — State machine - `src/NATS.Server/Protocol/NatsProtocol.cs` — Wire-level writing - `src/NATS.Server/Protocol/NatsHeaderParser.cs` - `src/NATS.Server/Protocol/ClientCommandMatrix.cs` - `src/NATS.Server/Protocol/MessageTraceContext.cs` - `src/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` + `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: 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`: ```bash # 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 ``` 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: ```bash 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 |