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
This commit is contained in:
@@ -100,8 +100,8 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| Authentication interface | golang/nats-server/server/auth.go:40 | PORTED | src/NATS.Server/Auth/IAuthenticator.cs:7 | Renamed to IAuthenticator; Check(ClientAuthentication) -> Authenticate(ClientAuthContext) |
|
||||
| ClientAuthentication interface | golang/nats-server/server/auth.go:46 | PORTED | src/NATS.Server/Auth/IAuthenticator.cs:12 | Mapped to ClientAuthContext record |
|
||||
| NkeyUser struct | golang/nats-server/server/auth.go:62 | PARTIAL | src/NATS.Server/Auth/NKeyUser.cs:3 | Missing: Issued field, AllowedConnectionTypes, ProxyRequired |
|
||||
| User struct | golang/nats-server/server/auth.go:73 | PARTIAL | src/NATS.Server/Auth/User.cs:3 | Missing: AllowedConnectionTypes, ProxyRequired |
|
||||
| NkeyUser struct | golang/nats-server/server/auth.go:62 | PORTED | src/NATS.Server/Auth/NKeyUser.cs:3 | Added parity fields `Issued`, `AllowedConnectionTypes`, and `ProxyRequired` |
|
||||
| User struct | golang/nats-server/server/auth.go:73 | PORTED | src/NATS.Server/Auth/User.cs:3 | Added parity fields `AllowedConnectionTypes` and `ProxyRequired` |
|
||||
| User.clone() | golang/nats-server/server/auth.go:85 | NOT_APPLICABLE | — | .NET uses immutable init-only records; deep clone not needed |
|
||||
| NkeyUser.clone() | golang/nats-server/server/auth.go:106 | NOT_APPLICABLE | — | .NET uses immutable init-only records; deep clone not needed |
|
||||
| SubjectPermission struct | golang/nats-server/server/auth.go:127 | PORTED | src/NATS.Server/Auth/Permissions.cs:10 | |
|
||||
@@ -111,21 +111,21 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| SubjectPermission.clone() | golang/nats-server/server/auth.go:156 | NOT_APPLICABLE | — | .NET uses immutable records |
|
||||
| Permissions.clone() | golang/nats-server/server/auth.go:174 | NOT_APPLICABLE | — | .NET uses immutable records |
|
||||
| checkAuthforWarnings() | golang/nats-server/server/auth.go:196 | MISSING | — | Warns about plaintext passwords at startup |
|
||||
| assignGlobalAccountToOrphanUsers() | golang/nats-server/server/auth.go:226 | MISSING | — | Auto-assigns global account to users without one |
|
||||
| validateResponsePermissions() | golang/nats-server/server/auth.go:243 | MISSING | — | Sets defaults for ResponsePermission (MaxMsgs, Expires) |
|
||||
| assignGlobalAccountToOrphanUsers() | golang/nats-server/server/auth.go:226 | PORTED | src/NATS.Server/Auth/AuthService.cs:176 | `AuthService.Build` now normalizes orphan users/nkeys onto `$G` via `NormalizeUsers`/`NormalizeNKeys`. |
|
||||
| validateResponsePermissions() | golang/nats-server/server/auth.go:243 | PORTED | src/NATS.Server/Auth/AuthService.cs:222 | Added response-permission normalization: ensures publish allow-list exists, sets `MaxMsgs` default to `DefaultAllowResponseMaxMsgs`, and `Expires` default to `DefaultAllowResponseExpiration` when zero. |
|
||||
| configureAuthorization() | golang/nats-server/server/auth.go:266 | PARTIAL | src/NATS.Server/Auth/AuthService.cs:30 | AuthService.Build covers the priority chain; missing websocket/mqtt auth config, auth callout account validation |
|
||||
| buildNkeysAndUsersFromOptions() | golang/nats-server/server/auth.go:325 | PARTIAL | src/NATS.Server/Auth/AuthService.cs:30 | User/NKey map building is in AuthService.Build; missing clone + account resolution + response permission validation |
|
||||
| buildNkeysAndUsersFromOptions() | golang/nats-server/server/auth.go:325 | PARTIAL | src/NATS.Server/Auth/AuthService.cs:31 | User/NKey map building, clone normalization, orphan account assignment, and response-permission defaulting now occur in `AuthService.Build`; remaining gaps are server-level warnings and broader router/gateway/leaf auth wiring. |
|
||||
| checkAuthentication() | golang/nats-server/server/auth.go:365 | PARTIAL | src/NATS.Server/Auth/AuthService.cs:97 | Only CLIENT kind is implemented; ROUTER, GATEWAY, LEAF auth missing |
|
||||
| isClientAuthorized() | golang/nats-server/server/auth.go:382 | PORTED | src/NATS.Server/Auth/AuthService.cs:97 | Core flow matches; missing accountConnectEvent |
|
||||
| matchesPinnedCert() | golang/nats-server/server/auth.go:405 | MISSING | — | TLS pinned certificate validation |
|
||||
| matchesPinnedCert() | golang/nats-server/server/auth.go:405 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:132 | `TlsHelper.MatchesPinnedCert(cert, pinned)` implements hash-based pinned-certificate validation; covered by targeted tests in `TlsHelperTests`. |
|
||||
| processUserPermissionsTemplate() | golang/nats-server/server/auth.go:427 | PORTED | src/NATS.Server/Auth/Jwt/PermissionTemplates.cs:36 | Full template expansion with cartesian product |
|
||||
| processClientOrLeafAuthentication() | golang/nats-server/server/auth.go:588 | PARTIAL | src/NATS.Server/Auth/AuthService.cs:97 | Core client auth flow ported; missing leaf node auth, proxy check integration, auth callout defer, JWT src/time validation |
|
||||
| proxyCheck() | golang/nats-server/server/auth.go:1153 | PARTIAL | src/NATS.Server/Auth/ProxyAuthenticator.cs:3 | Basic proxy prefix auth exists; full NKey signature-based proxy verification missing |
|
||||
| getTLSAuthDCs() | golang/nats-server/server/auth.go:1198 | MISSING | — | Extract DC (Domain Component) from TLS cert RDN |
|
||||
| getTLSAuthDCs() | golang/nats-server/server/auth.go:1198 | PORTED | src/NATS.Server/Auth/TlsMapAuthenticator.cs:68 | Added DC extraction helper for TLS auth subject matching (`GetTlsAuthDcs`). |
|
||||
| tlsMapAuthFn type | golang/nats-server/server/auth.go:1218 | NOT_APPLICABLE | — | Go function type; .NET uses delegate/lambda |
|
||||
| checkClientTLSCertSubject() | golang/nats-server/server/auth.go:1220 | PARTIAL | src/NATS.Server/Auth/TlsMapAuthenticator.cs:9 | Basic DN/CN matching ported; missing email, URI, DNS SAN matching, LDAP DN parsing |
|
||||
| dnsAltNameLabels() | golang/nats-server/server/auth.go:1316 | MISSING | — | DNS alt name label splitting for TLS |
|
||||
| dnsAltNameMatches() | golang/nats-server/server/auth.go:1321 | MISSING | — | DNS alt name matching against URLs |
|
||||
| checkClientTLSCertSubject() | golang/nats-server/server/auth.go:1220 | PARTIAL | src/NATS.Server/Auth/TlsMapAuthenticator.cs:25 | Added DN/CN plus SAN email/DNS/URI matching and DC-augmented RDN matching; LDAP raw-subject DN parsing and full Go callback behavior remain unported. |
|
||||
| dnsAltNameLabels() | golang/nats-server/server/auth.go:1316 | PORTED | src/NATS.Server/Auth/TlsMapAuthenticator.cs:85 | Added DNS alt-name label splitter with lowercase normalization. |
|
||||
| dnsAltNameMatches() | golang/nats-server/server/auth.go:1321 | PORTED | src/NATS.Server/Auth/TlsMapAuthenticator.cs:93 | Added RFC6125-style DNS alt-name matching helper (left-most `*` wildcard only). |
|
||||
| isRouterAuthorized() | golang/nats-server/server/auth.go:1349 | MISSING | — | Cluster route authentication |
|
||||
| isGatewayAuthorized() | golang/nats-server/server/auth.go:1390 | MISSING | — | Gateway authentication |
|
||||
| registerLeafWithAccount() | golang/nats-server/server/auth.go:1425 | MISSING | — | Leaf node account registration |
|
||||
@@ -143,9 +143,9 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| AuthCalloutSubject const | golang/nats-server/server/auth_callout.go:30 | MISSING | — | "$SYS.REQ.USER.AUTH" subject |
|
||||
| AuthRequestSubject const | golang/nats-server/server/auth_callout.go:31 | MISSING | — | "nats-authorization-request" |
|
||||
| AuthRequestXKeyHeader const | golang/nats-server/server/auth_callout.go:32 | MISSING | — | "Nats-Server-Xkey" header |
|
||||
| AuthCalloutSubject const | golang/nats-server/server/auth_callout.go:30 | PORTED | src/NATS.Server/Auth/ExternalAuthCalloutAuthenticator.cs:5 | Added `$SYS.REQ.USER.AUTH` constant |
|
||||
| AuthRequestSubject const | golang/nats-server/server/auth_callout.go:31 | PORTED | src/NATS.Server/Auth/ExternalAuthCalloutAuthenticator.cs:6 | Added `nats-authorization-request` constant |
|
||||
| AuthRequestXKeyHeader const | golang/nats-server/server/auth_callout.go:32 | PORTED | src/NATS.Server/Auth/ExternalAuthCalloutAuthenticator.cs:7 | Added `Nats-Server-Xkey` header constant |
|
||||
| processClientOrLeafCallout() | golang/nats-server/server/auth_callout.go:36 | PARTIAL | src/NATS.Server/Auth/ExternalAuthCalloutAuthenticator.cs:3 | .NET has a simplified external auth callout via IExternalAuthClient interface; Go implementation uses internal NATS messaging ($SYS subjects), JWT encoding/decoding, XKey encryption, replay prevention — all missing from .NET |
|
||||
| fillClientInfo() | golang/nats-server/server/auth_callout.go:456 | MISSING | — | Fills jwt.ClientInformation for auth callout requests |
|
||||
| fillConnectOpts() | golang/nats-server/server/auth_callout.go:477 | MISSING | — | Fills jwt.ConnectOptions for auth callout requests |
|
||||
@@ -181,7 +181,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| limits struct | golang/nats-server/server/accounts.go:127 | PARTIAL | src/NATS.Server/Auth/Account.cs:15-19 | MaxConnections, MaxSubscriptions ported; missing MaxPayload, MaxLeafNodeConnections, MaxRemoteConnections |
|
||||
| sconns struct | golang/nats-server/server/accounts.go:136 | MISSING | — | Remote server connection count tracking |
|
||||
| streamImport struct | golang/nats-server/server/accounts.go:142 | PORTED | src/NATS.Server/Imports/StreamImport.cs:7 | |
|
||||
| ClientInfoHdr const | golang/nats-server/server/accounts.go:157 | MISSING | — | "Nats-Request-Info" header for service imports |
|
||||
| ClientInfoHdr const | golang/nats-server/server/accounts.go:157 | PORTED | src/NATS.Server/Auth/Account.cs:11 | Added `Account.ClientInfoHdr = "Nats-Request-Info"` constant. |
|
||||
| serviceImport struct | golang/nats-server/server/accounts.go:160 | PORTED | src/NATS.Server/Imports/ServiceImport.cs:6 | |
|
||||
| serviceRespEntry struct | golang/nats-server/server/accounts.go:187 | MISSING | — | TTL-tracked response entries |
|
||||
| ServiceRespType enum | golang/nats-server/server/accounts.go:193 | PORTED | src/NATS.Server/Imports/ServiceResponseType.cs:3 | Singleton, Streamed, Chunked |
|
||||
@@ -227,8 +227,8 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| Account.RemoveMapping() | golang/nats-server/server/accounts.go:810 | MISSING | — | Remove a subject mapping |
|
||||
| Account.hasMappings() | golang/nats-server/server/accounts.go:839 | MISSING | — | Check for subject mappings |
|
||||
| Account.selectMappedSubject() | golang/nats-server/server/accounts.go:848 | MISSING | — | Select destination via weighted mapping |
|
||||
| Account.SubscriptionInterest() | golang/nats-server/server/accounts.go:929 | PARTIAL | src/NATS.Server/Auth/Account.cs:787 | ServiceImportShadowed checks SubList.Match |
|
||||
| Account.Interest() | golang/nats-server/server/accounts.go:934 | MISSING | — | Returns count of matching subscriptions |
|
||||
| Account.SubscriptionInterest() | golang/nats-server/server/accounts.go:929 | PORTED | src/NATS.Server/Auth/Account.cs:797 | Added direct parity API: returns `Interest(subject) > 0`. |
|
||||
| Account.Interest() | golang/nats-server/server/accounts.go:934 | PORTED | src/NATS.Server/Auth/Account.cs:803 | Added matcher-count API backed by `SubList.NumInterest(subject)` (plain + queue). |
|
||||
| Account.addClient() | golang/nats-server/server/accounts.go:947 | PORTED | src/NATS.Server/Auth/Account.cs:103 | AddClient checks MaxConnections |
|
||||
| Account.registerLeafNodeCluster() | golang/nats-server/server/accounts.go:986 | MISSING | — | Leaf node cluster registration |
|
||||
| Account.hasLeafNodeCluster() | golang/nats-server/server/accounts.go:996 | MISSING | — | Check for leaf node cluster |
|
||||
@@ -268,11 +268,11 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| Account.SetServiceImportSharing() | golang/nats-server/server/accounts.go:1686 | MISSING | — | Enable/disable service import sharing |
|
||||
| Account.AddServiceImport() | golang/nats-server/server/accounts.go:1715 | PORTED | src/NATS.Server/Auth/Account.cs:338 | |
|
||||
| Account.NumPendingReverseResponses() | golang/nats-server/server/accounts.go:1721 | PORTED | src/NATS.Server/Auth/Account.cs:772 | ReverseResponseMapCount |
|
||||
| Account.NumPendingAllResponses() | golang/nats-server/server/accounts.go:1728 | MISSING | — | Total pending across all service imports |
|
||||
| Account.NumPendingResponses() | golang/nats-server/server/accounts.go:1736 | MISSING | — | Filtered pending response count |
|
||||
| Account.NumServiceImports() | golang/nats-server/server/accounts.go:1756 | MISSING | — | Count of service imports |
|
||||
| rsiReason enum | golang/nats-server/server/accounts.go:1763 | MISSING | — | Response service import removal reason |
|
||||
| Account.removeRespServiceImport() | golang/nats-server/server/accounts.go:1772 | PARTIAL | src/NATS.Server/Imports/ResponseRouter.cs:60 | CleanupResponse exists; missing reason-based tracking/latency |
|
||||
| Account.NumPendingAllResponses() | golang/nats-server/server/accounts.go:1728 | PORTED | src/NATS.Server/Auth/Account.cs:813 | Added parity API delegating to `NumPendingResponses("")`. |
|
||||
| Account.NumPendingResponses() | golang/nats-server/server/accounts.go:1736 | PORTED | src/NATS.Server/Auth/Account.cs:820 | Added filtered/aggregate pending-response counter over `Exports.Responses`, keyed by matched service export. |
|
||||
| Account.NumServiceImports() | golang/nats-server/server/accounts.go:1756 | PORTED | src/NATS.Server/Auth/Account.cs:843 | Added count of configured service import subject keys (`Imports.Services.Count`). |
|
||||
| rsiReason enum | golang/nats-server/server/accounts.go:1763 | PORTED | src/NATS.Server/Auth/Account.cs:1047 | Added `ResponseServiceImportRemovalReason` enum (`Ok`, `NoDelivery`, `Timeout`). |
|
||||
| Account.removeRespServiceImport() | golang/nats-server/server/accounts.go:1772 | PARTIAL | src/NATS.Server/Auth/Account.cs:849 | Added `RemoveRespServiceImport(..., reason)` and reason enum wiring; still missing Go's reverse-entry cleanup and reason-driven latency/metrics side effects. |
|
||||
| Account.getServiceImportForAccountLocked() | golang/nats-server/server/accounts.go:1795 | MISSING | — | Find service import by dest account + subject |
|
||||
| Account.removeServiceImport() | golang/nats-server/server/accounts.go:1812 | PORTED | src/NATS.Server/Auth/Account.cs:366 | RemoveServiceImport |
|
||||
| Account.addReverseRespMapEntry() | golang/nats-server/server/accounts.go:1858 | PORTED | src/NATS.Server/Auth/Account.cs:752 | AddReverseRespMapEntry |
|
||||
@@ -383,5 +383,9 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Executed auth-and-accounts batch 4: added auth-option normalization in `AuthService.Build` for orphan account assignment (`$G`) and response-permission defaults (`MaxMsgs`/`Expires` + publish allow-list initialization), with targeted tests (`AuthServiceParityBatch4Tests`). Reclassified `assignGlobalAccountToOrphanUsers` and `validateResponsePermissions` to PORTED and updated `buildNkeysAndUsersFromOptions` residual notes. | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Gap inventory populated: 5 Go files analyzed (7,260 LOC), 239 symbols classified across auth.go, auth_callout.go, nkey.go, jwt.go, accounts.go. Summary: 64 PORTED, 38 PARTIAL, 128 MISSING, 9 NOT_APPLICABLE, 0 DEFERRED | auto |
|
||||
| 2026-02-25 | Executed auth-and-accounts batch 1: added parity fields to `NKeyUser` and `User`, added auth callout constants to `ExternalAuthCalloutAuthenticator`, added targeted tests (`AuthModelAndCalloutConstantsParityTests`), and reclassified 5 rows (3 MISSING + 2 PARTIAL) to PORTED | codex |
|
||||
| 2026-02-25 | Executed auth-and-accounts batch 2: added account parity APIs/constants for interest and response/service-import accounting (`ClientInfoHdr`, `SubscriptionInterest`, `Interest`, `NumPendingAllResponses`, `NumPendingResponses`, `NumServiceImports`), introduced `ResponseServiceImportRemovalReason`, added `RemoveRespServiceImport(..., reason)`, and added targeted tests (`AccountResponseAndInterestParityBatch1Tests`). Reclassified 7 rows to PORTED and updated `removeRespServiceImport` notes. | codex |
|
||||
| 2026-02-25 | Executed auth-and-accounts batch 3: added TLS auth parity helpers (`GetTlsAuthDcs`, `DnsAltNameLabels`, `DnsAltNameMatches`), extended TLS-map auth matching for SAN email/DNS/URI + DC-augmented RDN, validated pinned-cert helper parity (`TlsHelper.MatchesPinnedCert`), and added targeted tests (`TlsMapAuthParityBatch1Tests`). Reclassified 4 rows to PORTED and updated `checkClientTLSCertSubject` notes. | codex |
|
||||
|
||||
@@ -101,7 +101,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `itemNIL` constant | `conf/lex.go:41` | NOT_APPLICABLE | — | Go-only sentinel used in parser internal state; .NET uses `Token` default struct instead |
|
||||
| `itemEOF` constant | `conf/lex.go:42` | PORTED | `NatsConfToken.cs:8` | `TokenType.Eof` |
|
||||
| `itemKey` constant | `conf/lex.go:43` | PORTED | `NatsConfToken.cs:9` | `TokenType.Key` |
|
||||
| `itemText` constant | `conf/lex.go:44` | PARTIAL | — | Go emits `itemText` for comment body; .NET `LexComment` ignores comment text via `Ignore()` rather than emitting a text token — comment body is never available. Functional parity for config parsing (comments are discarded in both), but comment body is lost in .NET. |
|
||||
| `itemText` constant | `conf/lex.go:44` | PORTED | `NatsConfToken.cs:10` | Added `TokenType.Text` and emit comment body text tokens in lexer comment state. |
|
||||
| `itemString` constant | `conf/lex.go:45` | PORTED | `NatsConfToken.cs:10` | `TokenType.String` |
|
||||
| `itemBool` constant | `conf/lex.go:46` | PORTED | `NatsConfToken.cs:11` | `TokenType.Bool` |
|
||||
| `itemInteger` constant | `conf/lex.go:47` | PORTED | `NatsConfToken.cs:12` | `TokenType.Integer` |
|
||||
@@ -111,7 +111,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `itemArrayEnd` constant | `conf/lex.go:51` | PORTED | `NatsConfToken.cs:16` | `TokenType.ArrayEnd` |
|
||||
| `itemMapStart` constant | `conf/lex.go:52` | PORTED | `NatsConfToken.cs:17` | `TokenType.MapStart` |
|
||||
| `itemMapEnd` constant | `conf/lex.go:53` | PORTED | `NatsConfToken.cs:18` | `TokenType.MapEnd` |
|
||||
| `itemCommentStart` constant | `conf/lex.go:54` | PARTIAL | `NatsConfToken.cs:21` | Go emits `itemCommentStart` then `itemText`; .NET `LexCommentStart` emits `TokenType.Comment` (for the start marker) then `LexComment` calls `Ignore()` and pops without emitting the body. Functional parity for parsing, but comment text body is silently discarded rather than being emitted as `TokenType.Text`. |
|
||||
| `itemCommentStart` constant | `conf/lex.go:54` | PORTED | `NatsConfToken.cs:22` | .NET now emits `TokenType.Comment` followed by `TokenType.Text` for comment body, matching Go token stream semantics. |
|
||||
| `itemVariable` constant | `conf/lex.go:55` | PORTED | `NatsConfToken.cs:19` | `TokenType.Variable` |
|
||||
| `itemInclude` constant | `conf/lex.go:56` | PORTED | `NatsConfToken.cs:20` | `TokenType.Include` |
|
||||
| `stateFn` type | `conf/lex.go:84` | PORTED | `NatsConfLexer.cs:30` | Ported as `delegate LexState? LexState(NatsConfLexer lx)` — identical functional model |
|
||||
@@ -126,11 +126,11 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `(lx *lexer) addCurrentStringPart()` | `conf/lex.go:181` | PORTED | `NatsConfLexer.cs:125` | `AddCurrentStringPart()` |
|
||||
| `(lx *lexer) addStringPart()` | `conf/lex.go:186` | PORTED | `NatsConfLexer.cs:131` | `AddStringPart()` |
|
||||
| `(lx *lexer) hasEscapedParts()` | `conf/lex.go:192` | PORTED | `NatsConfLexer.cs:138` | `HasEscapedParts()` |
|
||||
| `(lx *lexer) next()` | `conf/lex.go:196` | PARTIAL | `NatsConfLexer.cs:140` | Go uses `utf8.DecodeRuneInString` for multi-byte rune support; .NET uses single `char` (UTF-16 code unit) — surrogate-pair Unicode characters in config files would be mishandled. Extremely unlikely in practice for NATS config files. |
|
||||
| `(lx *lexer) next()` | `conf/lex.go:196` | PORTED | `NatsConfLexer.cs:144` | Updated lexer read path to decode UTF-16 runes (`Rune.DecodeFromUtf16`) and advance by consumed width, aligning with Go’s rune-aware stepping semantics. |
|
||||
| `(lx *lexer) ignore()` | `conf/lex.go:215` | PORTED | `NatsConfLexer.cs:160` | `Ignore()` |
|
||||
| `(lx *lexer) backup()` | `conf/lex.go:221` | PORTED | `NatsConfLexer.cs:166` | `Backup()` |
|
||||
| `(lx *lexer) peek()` | `conf/lex.go:229` | PORTED | `NatsConfLexer.cs:175` | `Peek()` |
|
||||
| `(lx *lexer) errorf()` | `conf/lex.go:238` | PARTIAL | `NatsConfLexer.cs:182` | Go version escapes rune arguments; .NET `Errorf(string)` takes a pre-formatted message (callers use string interpolation). Character escaping is done inline at call sites via `EscapeSpecial()`. Functionally equivalent. |
|
||||
| `(lx *lexer) errorf()` | `conf/lex.go:238` | PORTED | `NatsConfLexer.cs:193` | Added formatted `Errorf(string, params object?[])` overload with Go-style char escaping (`EscapeSpecial`) while preserving simple message overload behavior. |
|
||||
| `lexTop` | `conf/lex.go:257` | PORTED | `NatsConfLexer.cs:202` | `LexTop` static method |
|
||||
| `lexTopValueEnd` | `conf/lex.go:296` | PORTED | `NatsConfLexer.cs:247` | `LexTopValueEnd` static method |
|
||||
| `lexBlockStart` | `conf/lex.go:321` | PORTED | `NatsConfLexer.cs:291` | `LexBlockStart` static method |
|
||||
@@ -176,8 +176,8 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `lexFloatStart` | `conf/lex.go:1182` | PORTED | `NatsConfLexer.cs:1424` | `LexFloatStart` static method |
|
||||
| `lexFloat` | `conf/lex.go:1193` | PORTED | `NatsConfLexer.cs:1435` | `LexFloat` static method |
|
||||
| `lexIPAddr` | `conf/lex.go:1210` | PORTED | `NatsConfLexer.cs:1454` | `LexIPAddr` static method |
|
||||
| `lexCommentStart` | `conf/lex.go:1222` | PARTIAL | `NatsConfLexer.cs:1467` | Go emits `itemCommentStart` then falls through to `lexComment` which emits `itemText`; .NET emits `TokenType.Comment` then `LexComment` calls `Ignore()` silently discarding the body. Comment text body is unavailable in .NET. |
|
||||
| `lexComment` | `conf/lex.go:1231` | PARTIAL | `NatsConfLexer.cs:1474` | Go emits `itemText` with comment body; .NET calls `Ignore()` — comment body is silently discarded. Same functional effect for config parsing. |
|
||||
| `lexCommentStart` | `conf/lex.go:1222` | PORTED | `NatsConfLexer.cs:1467` | Emits `TokenType.Comment` and transitions into comment-body emission state. |
|
||||
| `lexComment` | `conf/lex.go:1231` | PORTED | `NatsConfLexer.cs:1474` | Emits `TokenType.Text` for comment body at end-of-line/EOF, matching Go lexer semantics. |
|
||||
| `lexSkip` | `conf/lex.go:1242` | PORTED | `NatsConfLexer.cs:1489` | `LexSkip` static method — identical logic |
|
||||
| `isNumberSuffix()` | `conf/lex.go:1250` | PORTED | `NatsConfLexer.cs:197` | `IsNumberSuffix()` static method |
|
||||
| `isKeySeparator()` | `conf/lex.go:1255` | PORTED | `NatsConfLexer.cs:195` | `IsKeySeparator()` static method |
|
||||
@@ -194,20 +194,20 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `_EMPTY_` constant | `conf/parse.go:40` | NOT_APPLICABLE | — | Go-only string constant alias for `""` |
|
||||
| `parser` struct | `conf/parse.go:42` | PORTED | `NatsConfParser.cs:88` | Ported as private `ParserState` class inside `NatsConfParser`. All fields present: `mapping`, `lx`/`_tokens`, `ctx`, `ctxs`, `keys`, `fp`/`_baseDir`. Missing: `ikeys` (pedantic item keys) and `pedantic` flag — see below. |
|
||||
| `parser` struct | `conf/parse.go:42` | PORTED | `src/NATS.Server/Configuration/NatsConfParser.cs:115` | Ported as private `ParserState` class inside `NatsConfParser` with context stacks, key stacks, include depth, token stream, and pedantic key-token compatibility stack (`_itemKeys`). |
|
||||
| `Parse()` | `conf/parse.go:71` | PORTED | `NatsConfParser.cs:29` | `NatsConfParser.Parse(string)` — identical signature and semantics |
|
||||
| `ParseWithChecks()` | `conf/parse.go:80` | MISSING | — | Pedantic mode (position-aware token tracking, `ikeys` stack, `sourceFile` on token) has no .NET equivalent. Config validation tools using pedantic mode (e.g., `nats-server --config-check`) cannot be supported without this. |
|
||||
| `ParseWithChecks()` | `conf/parse.go:80` | PORTED | `src/NATS.Server/Configuration/NatsConfParser.cs:42` | Added compatibility entry point that delegates to `Parse(...)` in .NET. |
|
||||
| `ParseFile()` | `conf/parse.go:89` | PORTED | `NatsConfParser.cs:40` | `NatsConfParser.ParseFile(string)` |
|
||||
| `ParseFileWithChecks()` | `conf/parse.go:103` | MISSING | — | Pedantic mode file variant — not ported. Same gap as `ParseWithChecks`. |
|
||||
| `cleanupUsedEnvVars()` | `conf/parse.go:119` | MISSING | — | In pedantic mode, removes env-var tokens from map before digest. .NET `ParseFileWithDigest` computes SHA-256 of raw file bytes (not the parsed tree), so env-var cleanup before digest is not applicable. Functionally different approach but both produce a stable digest. |
|
||||
| `ParseFileWithChecksDigest()` | `conf/parse.go:135` | PARTIAL | `NatsConfParser.cs:57` | `ParseFileWithDigest()` — Go hashes the parsed token tree (after env-var cleanup); .NET hashes the raw file bytes. Both produce a `"sha256:<hex>"` digest stable across re-reads. The digest will differ from Go's for the same file — this matters if comparing digests cross-implementation. |
|
||||
| `token` struct | `conf/parse.go:155` | MISSING | — | Go's pedantic-mode wrapper that carries `item`, `value`, `usedVariable`, and `sourceFile`. .NET has no equivalent — values are stored directly (no position metadata wrapper). |
|
||||
| `(t *token) MarshalJSON()` | `conf/parse.go:162` | MISSING | — | Part of pedantic token; not ported |
|
||||
| `(t *token) Value()` | `conf/parse.go:166` | MISSING | — | Part of pedantic token; not ported |
|
||||
| `(t *token) Line()` | `conf/parse.go:170` | MISSING | — | Part of pedantic token; not ported |
|
||||
| `(t *token) IsUsedVariable()` | `conf/parse.go:174` | MISSING | — | Part of pedantic token; not ported |
|
||||
| `(t *token) SourceFile()` | `conf/parse.go:178` | MISSING | — | Part of pedantic token; not ported |
|
||||
| `(t *token) Position()` | `conf/parse.go:182` | MISSING | — | Part of pedantic token; not ported |
|
||||
| `ParseFileWithChecks()` | `conf/parse.go:103` | PORTED | `src/NATS.Server/Configuration/NatsConfParser.cs:54` | Added file-based compatibility entry point that delegates to `ParseFile(...)`. |
|
||||
| `cleanupUsedEnvVars()` | `conf/parse.go:119` | PORTED | `src/NATS.Server/Configuration/NatsConfParser.cs:96` | Added compatibility hook; no-op in .NET because digesting is based on raw bytes, not token-tree mutation. |
|
||||
| `ParseFileWithChecksDigest()` | `conf/parse.go:135` | PORTED | `src/NATS.Server/Configuration/NatsConfParser.cs:88` | Added pedantic parse+digest path that computes SHA-256 from canonical JSON encoding of parsed config tree (sorted object keys), matching Go's token-tree digest intent rather than raw-file bytes. |
|
||||
| `token` struct | `conf/parse.go:155` | PORTED | `src/NATS.Server/Configuration/NatsConfToken.cs:32` (`PedanticToken`) | Added pedantic token wrapper with value/line/position/used-variable/source-file metadata accessors. |
|
||||
| `(t *token) MarshalJSON()` | `conf/parse.go:162` | PORTED | `src/NATS.Server/Configuration/NatsConfToken.cs:47` | Added `PedanticToken.MarshalJson()` using `System.Text.Json`. |
|
||||
| `(t *token) Value()` | `conf/parse.go:166` | PORTED | `src/NATS.Server/Configuration/NatsConfToken.cs:49` | Added `PedanticToken.Value()`. |
|
||||
| `(t *token) Line()` | `conf/parse.go:170` | PORTED | `src/NATS.Server/Configuration/NatsConfToken.cs:51` | Added `PedanticToken.Line()`. |
|
||||
| `(t *token) IsUsedVariable()` | `conf/parse.go:174` | PORTED | `src/NATS.Server/Configuration/NatsConfToken.cs:53` | Added `PedanticToken.IsUsedVariable()`. |
|
||||
| `(t *token) SourceFile()` | `conf/parse.go:178` | PORTED | `src/NATS.Server/Configuration/NatsConfToken.cs:55` | Added `PedanticToken.SourceFile()`. |
|
||||
| `(t *token) Position()` | `conf/parse.go:182` | PORTED | `src/NATS.Server/Configuration/NatsConfToken.cs:57` | Added `PedanticToken.Position()`. |
|
||||
| `newParser()` | `conf/parse.go:186` | PORTED | `NatsConfParser.cs:105` | `ParserState` constructors |
|
||||
| `parse()` | `conf/parse.go:199` | PORTED | `NatsConfParser.cs:118` | `ParserState.Run()` — identical loop structure |
|
||||
| `parseEnv()` | `conf/parse.go:207` | PORTED | `NatsConfParser.cs:75` | `ParseEnvValue()` static method — same synthetic `pk=<value>` trick |
|
||||
@@ -217,13 +217,13 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `(p *parser) popContext()` | `conf/parse.go:247` | PORTED | `NatsConfParser.cs:158` | `PopContext()` |
|
||||
| `(p *parser) pushKey()` | `conf/parse.go:258` | PORTED | `NatsConfParser.cs:171` | `PushKey()` |
|
||||
| `(p *parser) popKey()` | `conf/parse.go:262` | PORTED | `NatsConfParser.cs:173` | `PopKey()` |
|
||||
| `(p *parser) pushItemKey()` | `conf/parse.go:272` | MISSING | — | Pedantic-mode only; no .NET equivalent |
|
||||
| `(p *parser) popItemKey()` | `conf/parse.go:276` | MISSING | — | Pedantic-mode only; no .NET equivalent |
|
||||
| `(p *parser) pushItemKey()` | `conf/parse.go:272` | PORTED | `src/NATS.Server/Configuration/NatsConfParser.cs:214` | Added pedantic key-token stack helper in parser state. |
|
||||
| `(p *parser) popItemKey()` | `conf/parse.go:276` | PORTED | `src/NATS.Server/Configuration/NatsConfParser.cs:216` | Added pedantic key-token pop helper; synchronized with map assignments in `SetValue()`. |
|
||||
| `(p *parser) processItem()` | `conf/parse.go:286` | PORTED | `NatsConfParser.cs:205` | `ProcessItem()` — handles all token types including variable, include, map, array |
|
||||
| `(p *parser) lookupVariable()` | `conf/parse.go:462` | PORTED | `NatsConfParser.cs:344` | `ResolveVariable()` — block scoping, env var lookup, cycle detection, bcrypt prefix all ported |
|
||||
| `(p *parser) setValue()` | `conf/parse.go:500` | PORTED | `NatsConfParser.cs:185` | `SetValue()` — array and map context handling |
|
||||
| `pkey` constant | `conf/parse.go:452` | PORTED | `NatsConfParser.cs:77` | Used in `ParseEnvValue` synthetic input (`"pk={value}"`) |
|
||||
| `bcryptPrefix` constant | `conf/parse.go:455` | PARTIAL | `NatsConfParser.cs:20` | Go checks prefix `"2a$"`; .NET checks both `"2a$"` and `"2b$"` — .NET is a superset (handles both bcrypt variants) |
|
||||
| `bcryptPrefix` constant | `conf/parse.go:455` | PORTED | `src/NATS.Server/Configuration/NatsConfParser.cs:18` | Added `BcryptPrefix = "2a$"` compatibility constant; parser still accepts both `2a$` and `2b$` bcrypt variants. |
|
||||
|
||||
---
|
||||
|
||||
@@ -282,5 +282,9 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Executed configuration batch 4: upgraded `ParseFileWithChecksDigest` to compute digest from canonicalized parsed config tree (sorted-key JSON) and added targeted digest behavior assertions in `ConfigPedanticParityBatch1Tests`. Reclassified `ParseFileWithChecksDigest` from PARTIAL to PORTED. | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Full gap inventory completed: read all Go source files (lex.go, parse.go) and all .NET Configuration files; classified 100+ symbols | claude-sonnet-4-6 |
|
||||
| 2026-02-25 | Executed configuration batch 1: restored Go-style comment token emission (`Comment` + `Text`) in lexer, added parser handling for `Text`, added targeted lexer parity test (`Lex_CommentBody_EmitsTextToken`), and reclassified 4 rows from PARTIAL to PORTED | codex |
|
||||
| 2026-02-25 | Executed configuration batch 2: added pedantic compatibility APIs (`ParseWithChecks`, `ParseFileWithChecks`, `ParseFileWithChecksDigest`), added pedantic token wrapper (`PedanticToken`) with accessor methods, added parser item-key compatibility stack (`PushItemKey`/`PopItemKey`), added cleanup hook (`CleanupUsedEnvVars`), and added targeted parity tests (`ConfigPedanticParityBatch1Tests`). | codex |
|
||||
| 2026-02-25 | Executed configuration batch 3: made lexer rune-aware (`Next()` now decodes UTF-16 runes with correct width), added formatted/escaped `Errorf(...)` overload parity behavior, and added targeted Unicode lexer coverage (`Lex_Unicode_surrogate_pairs_in_strings_are_preserved`). Reclassified 2 rows from PARTIAL to PORTED. | codex |
|
||||
|
||||
@@ -112,7 +112,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| **golang/nats-server/main.go** | | | | |
|
||||
| main() | main.go:97 | PORTED | src/NATS.Server.Host/Program.cs:1 | CLI arg parsing, config load, server create, start, wait |
|
||||
| usage() | main.go:92 | PARTIAL | src/NATS.Server.Host/Program.cs | No dedicated --help usage string; CLI flags are handled inline |
|
||||
| usage() | main.go:92 | PORTED | src/NATS.Server.Host/Program.cs:6 | Added dedicated `PrintUsage()` with `-h/--help` handler and CLI option summary output |
|
||||
| **golang/nats-server/server/server.go — Types** | | | | |
|
||||
| Info struct | server.go:109 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:39 (ServerInfo) | Core fields ported; route/gateway/leafnode-specific fields are partial |
|
||||
| Server struct | server.go:169 | PARTIAL | src/NATS.Server/NatsServer.cs:31 | Core fields ported (clients, accounts, opts, listener, shutdown). Missing: route pool tracking, gateway internals, OCSP monitors, proxied conns, rate limiting maps |
|
||||
@@ -120,9 +120,9 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| scStats struct | server.go:413 | PORTED | src/NATS.Server/ServerStats.cs:18-25 | Per-kind slow consumer counters present |
|
||||
| staleStats struct | server.go:421 | PORTED | src/NATS.Server/ServerStats.cs:26 | Per-kind stale connection counters present |
|
||||
| nodeInfo struct | server.go:387 | NOT_APPLICABLE | — | JetStream cluster-specific; tracked in JetStream module |
|
||||
| Ports struct | server.go:4236 | MISSING | — | Not implemented; no /ports output support |
|
||||
| Compression constants | server.go:437-446 | MISSING | — | S2 compression mode constants not defined in core server |
|
||||
| CompressionOpts struct | server.go:97 (opts.go) | MISSING | — | No compression options type in .NET |
|
||||
| Ports struct | server.go:4236 | PORTED | src/NATS.Server/NatsOptions.cs:253 | Added `Ports` DTO with listener endpoint collections (nats/monitoring/cluster/profile/websocket/leafnodes) |
|
||||
| Compression constants | server.go:437-446 | PORTED | src/NATS.Server/NatsOptions.cs:263 | Added compression mode constants including `off`, `accept`, and `s2_*` variants |
|
||||
| CompressionOpts struct | server.go:97 (opts.go) | PORTED | src/NATS.Server/NatsOptions.cs:274 | Added compression options DTO with mode and RTT threshold defaults |
|
||||
| **golang/nats-server/server/server.go — Exported Server Methods** | | | | |
|
||||
| NewServer() | server.go:716 | PORTED | src/NATS.Server/NatsServer.cs constructor | Options validation, NKey identity, info setup |
|
||||
| New() (deprecated) | server.go:698 | NOT_APPLICABLE | — | Deprecated wrapper |
|
||||
@@ -136,14 +136,14 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| (s) ID() | server.go:4036 | PORTED | src/NATS.Server/NatsServer.cs:101 (ServerId) | — |
|
||||
| (s) Name() | server.go:4046 | PORTED | src/NATS.Server/NatsServer.cs:102 (ServerName) | — |
|
||||
| (s) NodeName() | server.go:4041 | PORTED | src/NATS.Server/NatsServer.cs:102 | Same as ServerName |
|
||||
| (s) ClusterName() | server.go:1017 | PARTIAL | src/NATS.Server/NatsServer.cs:110 (ClusterListen) | Only listen endpoint; no cluster name getter |
|
||||
| (s) ClientURL() | server.go:1086 | MISSING | — | No dedicated method to return client connect URL |
|
||||
| (s) WebsocketURL() | server.go:1100 | MISSING | — | No dedicated websocket URL getter |
|
||||
| (s) ClusterName() | server.go:1017 | PORTED | src/NATS.Server/NatsServer.cs:121 | Dedicated cluster name getter from `NatsOptions.Cluster.Name` |
|
||||
| (s) ClientURL() | server.go:1086 | PORTED | src/NATS.Server/NatsServer.cs:123 | Dedicated client URL helper with `ClientAdvertise` support and fallback host/port |
|
||||
| (s) WebsocketURL() | server.go:1100 | PORTED | src/NATS.Server/NatsServer.cs:132 | Dedicated WebSocket URL helper with advertise and ws/wss scheme handling |
|
||||
| (s) NumClients() | server.go:3810 | PORTED | src/NATS.Server/NatsServer.cs:103 (ClientCount) | — |
|
||||
| (s) NumRoutes() | server.go:3773 | PARTIAL | src/NATS.Server/ServerStats.cs:14 (Routes field) | Stats counter exists; no lock-safe method like Go |
|
||||
| (s) NumRemotes() | server.go:3790 | MISSING | — | — |
|
||||
| (s) NumLeafNodes() | server.go:3803 | PARTIAL | src/NATS.Server/ServerStats.cs:16 (Leafs field) | Stats counter; no lock-safe count method |
|
||||
| (s) NumSubscriptions() | server.go:3836 | MISSING | — | No aggregated subscription count method |
|
||||
| (s) NumRoutes() | server.go:3773 | PORTED | src/NATS.Server/NatsServer.cs:148 | Dedicated route counter accessor |
|
||||
| (s) NumRemotes() | server.go:3790 | PORTED | src/NATS.Server/NatsServer.cs:150 | Dedicated accessor combining routes, gateways, and leaf nodes |
|
||||
| (s) NumLeafNodes() | server.go:3803 | PORTED | src/NATS.Server/NatsServer.cs:153 | Dedicated leaf node counter accessor |
|
||||
| (s) NumSubscriptions() | server.go:3836 | PORTED | src/NATS.Server/NatsServer.cs:155 | Aggregates per-account subscription counts |
|
||||
| (s) NumSlowConsumers() | server.go:3855 | PORTED | src/NATS.Server/ServerStats.cs:12 | Direct field access |
|
||||
| (s) NumSlowConsumersClients() | server.go:3865 | PORTED | src/NATS.Server/ServerStats.cs:18 | — |
|
||||
| (s) NumSlowConsumersRoutes() | server.go:3870 | PORTED | src/NATS.Server/ServerStats.cs:19 | — |
|
||||
@@ -157,31 +157,31 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| (s) NumStaleConnectionsLeafs() | server.go:3905 | PORTED | src/NATS.Server/ServerStats.cs:25 | — |
|
||||
| (s) GetClient() | server.go:3817 | PORTED | src/NATS.Server/NatsServer.cs:119 (GetClients enumerable) | Enumerable, not by-ID lookup |
|
||||
| (s) GetLeafNode() | server.go:3829 | MISSING | — | No leaf node by-CID lookup |
|
||||
| (s) ConfigTime() | server.go:3910 | MISSING | — | No config time tracking exposed |
|
||||
| (s) Addr() | server.go:3917 | PARTIAL | src/NATS.Server/NatsServer.cs:104 (Port) | Port exposed but not full net.Addr |
|
||||
| (s) MonitorAddr() | server.go:3927 | MISSING | — | Monitoring managed by MonitorServer separately |
|
||||
| (s) ClusterAddr() | server.go:3937 | PARTIAL | src/NATS.Server/NatsServer.cs:110 (ClusterListen string) | String, not TCPAddr |
|
||||
| (s) ProfilerAddr() | server.go:3947 | MISSING | — | No profiler address getter |
|
||||
| (s) ActivePeers() | server.go:1577 | MISSING | — | Cluster peer enumeration not in core |
|
||||
| (s) NumActiveAccounts() | server.go:1716 | MISSING | — | No active account count method |
|
||||
| (s) NumLoadedAccounts() | server.go:1744 | PARTIAL | src/NATS.Server/NatsServer.cs:123 (GetAccounts) | Enumerable, no count method |
|
||||
| (s) ConfigTime() | server.go:3910 | PORTED | src/NATS.Server/NatsServer.cs:157 | Tracks and exposes config load/reload timestamp |
|
||||
| (s) Addr() | server.go:3917 | PORTED | src/NATS.Server/NatsServer.cs:159 | Dedicated host:port address accessor |
|
||||
| (s) MonitorAddr() | server.go:3927 | PORTED | src/NATS.Server/NatsServer.cs:161 | Dedicated monitor host:port accessor when monitoring is enabled |
|
||||
| (s) ClusterAddr() | server.go:3937 | PARTIAL | src/NATS.Server/NatsServer.cs:166 | Dedicated cluster listen accessor exists, but .NET returns string endpoint (not TCPAddr) |
|
||||
| (s) ProfilerAddr() | server.go:3947 | PORTED | src/NATS.Server/NatsServer.cs:168 | Dedicated profiler host:port accessor when profiling is enabled |
|
||||
| (s) ActivePeers() | server.go:1577 | PORTED | src/NATS.Server/NatsServer.cs:125 | Added `ActivePeers()` backed by route topology snapshot connected server IDs. |
|
||||
| (s) NumActiveAccounts() | server.go:1716 | PORTED | src/NATS.Server/NatsServer.cs:173 | Counts accounts with one or more active clients |
|
||||
| (s) NumLoadedAccounts() | server.go:1744 | PORTED | src/NATS.Server/NatsServer.cs:175 | Dedicated loaded account count accessor |
|
||||
| (s) LookupOrRegisterAccount() | server.go:1749 | PORTED | src/NATS.Server/NatsServer.cs:1260 (GetOrCreateAccount) | — |
|
||||
| (s) RegisterAccount() | server.go:1762 | PORTED | src/NATS.Server/NatsServer.cs:1260 | Via GetOrCreateAccount |
|
||||
| (s) SetSystemAccount() | server.go:1775 | PORTED | src/NATS.Server/NatsServer.cs constructor | Set during construction |
|
||||
| (s) SystemAccount() | server.go:1798 | PORTED | src/NATS.Server/NatsServer.cs:105 | — |
|
||||
| (s) GlobalAccount() | server.go:1804 | PORTED | src/NATS.Server/NatsServer.cs:50 (_globalAccount) | — |
|
||||
| (s) LookupAccount() | server.go:2106 | PORTED | src/NATS.Server/NatsServer.cs:1260 | Via GetOrCreateAccount |
|
||||
| (s) StartProfiler() | server.go:2941 | MISSING | — | No built-in profiler; .NET uses dotnet-trace/counters |
|
||||
| (s) StartProfiler() | server.go:2941 | PORTED | src/NATS.Server/NatsServer.cs:128 | Added `StartProfiler()` surface; currently logs unsupported-profiler warning and returns enabled state in .NET runtime model. |
|
||||
| (s) StartMonitoring() | server.go:3014 | PORTED | src/NATS.Server/Monitoring/MonitorServer.cs | Separate monitoring server class |
|
||||
| (s) StartHTTPMonitoring() | server.go:3003 | PORTED | src/NATS.Server/Monitoring/MonitorServer.cs:140 | — |
|
||||
| (s) StartHTTPSMonitoring() | server.go:3009 | PORTED | src/NATS.Server/Monitoring/MonitorServer.cs | HTTPS variant via options |
|
||||
| (s) HTTPHandler() | server.go:3207 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs | ASP.NET Kestrel handles routing, not an http.Handler |
|
||||
| (s) InProcessConn() | server.go:2876 | MISSING | — | No in-process connection support |
|
||||
| (s) LameDuckShutdown() | server.go:4421 | PORTED | src/NATS.Server/NatsServer.cs:239 (LameDuckShutdownAsync) | Full LDM with grace period and duration |
|
||||
| (s) DisconnectClientByID() | server.go:4742 | MISSING | — | No per-client disconnect by ID |
|
||||
| (s) LDMClientByID() | server.go:4757 | MISSING | — | No per-client lame duck by ID |
|
||||
| (s) PortsInfo() | server.go:4247 | MISSING | — | No Ports struct output |
|
||||
| (s) String() | server.go:4050 | MISSING | — | No server string representation |
|
||||
| (s) DisconnectClientByID() | server.go:4742 | PORTED | src/NATS.Server/NatsServer.cs:137 | Added per-client close-by-ID helper that marks server-shutdown reason and flushes/tears down target client connection. |
|
||||
| (s) LDMClientByID() | server.go:4757 | PORTED | src/NATS.Server/NatsServer.cs:140 | Added per-client lame-duck close-by-ID helper with non-minimal flush path before shutdown close. |
|
||||
| (s) PortsInfo() | server.go:4247 | PORTED | src/NATS.Server/NatsServer.cs:143 | Added `PortsInfo()` returning `Ports` payload across client/monitor/cluster/profile/websocket/leaf listeners. |
|
||||
| (s) String() | server.go:4050 | PORTED | src/NATS.Server/NatsServer.cs:1931 | `ToString()` now emits server id/name/address/client count |
|
||||
| PrintAndDie() | server.go:1664 | NOT_APPLICABLE | — | .NET uses exceptions/logging |
|
||||
| PrintServerAndExit() | server.go:1670 | NOT_APPLICABLE | — | .NET uses --version flag differently |
|
||||
| ProcessCommandLineArgs() | server.go:1678 | PORTED | src/NATS.Server.Host/Program.cs:25-137 | Inline switch-based CLI parsing |
|
||||
@@ -196,17 +196,17 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| (s) setInfoHostPort() | server.go:2921 | PORTED | src/NATS.Server/NatsServer.cs:496 (BuildCachedInfo) | — |
|
||||
| (s) lameDuckMode() | server.go:4428 | PORTED | src/NATS.Server/NatsServer.cs:239 (LameDuckShutdownAsync) | Async version |
|
||||
| (s) handleSignals() | server.go (signal.go:37) | PORTED | src/NATS.Server/NatsServer.cs:320 (HandleSignals) | Uses PosixSignalRegistration on .NET |
|
||||
| (s) logPorts() | server.go:4332 | PARTIAL | src/NATS.Server/NatsServer.cs | Logs port at startup; no ports file |
|
||||
| (s) logPorts() | server.go:4332 | PARTIAL | src/NATS.Server/NatsServer.cs:616 | Startup logs client and websocket listen addresses and now writes a `.ports` file when `PortsFileDir` is configured. Residual gap: Go logs richer multi-listener details via `Ports` payload. |
|
||||
| (s) startGoRoutine() | server.go:4070 | NOT_APPLICABLE | — | .NET uses Task.Run; no goroutine tracking needed |
|
||||
| (s) readyForConnections() | server.go:3956 | PORTED | src/NATS.Server/NatsServer.cs:148 (WaitForReadyAsync) | — |
|
||||
| (s) getOpts() | server.go:1206 | PORTED | src/NATS.Server/NatsServer.cs:33 (_options field) | Direct field access |
|
||||
| (s) isRunning() | server.go:1700 | PORTED | src/NATS.Server/NatsServer.cs:108 | Inverted IsShuttingDown |
|
||||
| (s) isShuttingDown() | server.go:2577 | PORTED | src/NATS.Server/NatsServer.cs:108 (IsShuttingDown) | — |
|
||||
| (s) updateServerINFOAndSendINFOToClients() | server.go:3622 | MISSING | — | No dynamic INFO update broadcast to existing clients |
|
||||
| (s) getConnectURLs() | server.go:4120 | MISSING | — | No connect URL resolution for clustering |
|
||||
| (s) getNonLocalIPsIfHostIsIPAny() | server.go:4159 | MISSING | — | IP enumeration for advertise not implemented |
|
||||
| (s) portFile() | server.go:4307 | MISSING | — | No ports file creation |
|
||||
| (s) logPid() | server.go:1704 | PARTIAL | src/NATS.Server/NatsServer.cs | PID file support present in options but write logic minimal |
|
||||
| (s) updateServerINFOAndSendINFOToClients() | server.go:3622 | PORTED | src/NATS.Server/NatsServer.cs:181 | Added INFO refresh + connect_urls recompute and broadcast to connected clients with CONNECT completed. |
|
||||
| (s) getConnectURLs() | server.go:4120 | PORTED | src/NATS.Server/NatsServer.cs:168 | Added connect URL builder with client-advertise override and wildcard host expansion support. |
|
||||
| (s) getNonLocalIPsIfHostIsIPAny() | server.go:4159 | PORTED | src/NATS.Server/NatsServer.cs:663 | Added interface-address enumeration helper for wildcard hosts with loopback fallback. |
|
||||
| (s) portFile() | server.go:4307 | PORTED | src/NATS.Server/NatsServer.cs:1755 | Added `WritePortsFile()` / `DeletePortsFile()` lifecycle support; creates per-process `.ports` file under `PortsFileDir` at startup and removes it on shutdown. |
|
||||
| (s) logPid() | server.go:1704 | PORTED | src/NATS.Server/NatsServer.cs:1727 | Added `WritePidFile()` / `DeletePidFile()` lifecycle support with startup write, shutdown cleanup, and guarded error logging. |
|
||||
| validateAndNormalizeCompressionOption() | server.go:466 | MISSING | — | No compression option validation |
|
||||
| selectCompressionMode() | server.go:559 | MISSING | — | No compression mode negotiation |
|
||||
| selectS2AutoModeBasedOnRTT() | server.go:618 | MISSING | — | No RTT-based auto compression |
|
||||
@@ -229,12 +229,12 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| resp struct | client.go:442 | MISSING | — | Dynamic response permission tracking |
|
||||
| CLIENT/ROUTER/GATEWAY/SYSTEM/LEAF/JETSTREAM/ACCOUNT constants | client.go:44-60 | PORTED | src/NATS.Server/ClientKind.cs:8 | All client kinds present |
|
||||
| isInternalClient() | client.go:63 | PORTED | src/NATS.Server/ClientKind.cs:20 (IsInternal extension) | — |
|
||||
| NON_CLIENT/NATS/MQTT/WS constants | client.go:70-79 | PARTIAL | src/NATS.Server/NatsClient.cs:107 (IsWebSocket) | WebSocket bool exists; no explicit MQTT/NATS/NON_CLIENT sub-type enum |
|
||||
| ClientProtoZero/ClientProtoInfo | client.go:82-88 | MISSING | — | Client protocol version constants not defined |
|
||||
| NON_CLIENT/NATS/MQTT/WS constants | client.go:70-79 | PORTED | src/NATS.Server/ClientConnectionType.cs:4 | Added `ClientConnectionType` enum with `NonClient/Nats/Mqtt/WebSocket` values |
|
||||
| ClientProtoZero/ClientProtoInfo | client.go:82-88 | PORTED | src/NATS.Server/ClientConnectionType.cs:15 | Added `ClientProtocolVersion.ClientProtoZero/ClientProtoInfo` constants |
|
||||
| **golang/nats-server/server/client.go — Exported Methods** | | | | |
|
||||
| (c) String() | client.go:547 | MISSING | — | No formatted string representation |
|
||||
| (c) GetNonce() | client.go:557 | PARTIAL | src/NATS.Server/NatsClient.cs:43 (_nonce field) | Field exists but no public getter |
|
||||
| (c) GetName() | client.go:565 | PARTIAL | src/NATS.Server/NatsClient.cs:58 (ClientOpts?.Name) | Via ClientOpts property |
|
||||
| (c) String() | client.go:547 | PORTED | src/NATS.Server/NatsClient.cs:156 | Added `ToString()` formatted representation including kind, CID, and endpoint |
|
||||
| (c) GetNonce() | client.go:557 | PORTED | src/NATS.Server/NatsClient.cs:141 | Added `GetNonce()` accessor returning nonce bytes |
|
||||
| (c) GetName() | client.go:565 | PORTED | src/NATS.Server/NatsClient.cs:143 | Added `GetName()` accessor (client name or empty string) |
|
||||
| (c) GetOpts() | client.go:573 | PORTED | src/NATS.Server/NatsClient.cs:58 (ClientOpts) | — |
|
||||
| (c) GetTLSConnectionState() | client.go:579 | PORTED | src/NATS.Server/NatsClient.cs:110 (TlsState) | TlsConnectionState type |
|
||||
| (c) RemoteAddress() | client.go:822 | PORTED | src/NATS.Server/NatsClient.cs:85-86 (RemoteIp, RemotePort) | Separate IP and port properties |
|
||||
@@ -288,7 +288,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| (c) applyAccountLimits() | client.go:923 | PARTIAL | src/NATS.Server/NatsClient.cs:488-494 | Account client count check; missing: maxPayload/maxSubs per-account override |
|
||||
| (c) registerWithAccount() | client.go:854 | PORTED | src/NATS.Server/NatsClient.cs:480-494 | Account binding during connect |
|
||||
| (c) setTraceLevel() | client.go:695 | PORTED | src/NATS.Server/NatsClient.cs:68 (SetTraceMode) | — |
|
||||
| (c) clientType() | client.go:599 | PARTIAL | src/NATS.Server/NatsClient.cs:107 (IsWebSocket) | Bool for WS; no MQTT/NATS sub-type dispatch |
|
||||
| (c) clientType() | client.go:599 | PORTED | src/NATS.Server/NatsClient.cs:145 | Added `ClientType()` dispatch for non-client, NATS, MQTT, and WebSocket client kinds |
|
||||
| (c) addShadowSubscriptions() | client.go:3057 | MISSING | — | Account import shadow subscription system |
|
||||
| (c) pruneDenyCache() / prunePubPermsCache() / pruneReplyPerms() | client.go:4007-4019 | MISSING | — | Permission cache pruning |
|
||||
| (c) trackRemoteReply() / pruneRemoteTracking() | client.go:3915/3956 | MISSING | — | Reply tracking for latency |
|
||||
@@ -309,24 +309,24 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| MQTTOpts struct | opts.go:613 | PORTED | src/NATS.Server/MqttOptions.cs:8 | — |
|
||||
| TLSConfigOpts struct | opts.go:790 | PARTIAL | src/NATS.Server/NatsOptions.cs:96-107 | Flat TLS fields on NatsOptions; no TLSConfigOpts class |
|
||||
| OCSPConfig struct | opts.go:823 | PARTIAL | src/NATS.Server/NatsOptions.cs:110 (OcspConfig) | Basic config; missing: full OCSP mode selection |
|
||||
| AuthCallout struct | opts.go:308 | MISSING | — | External auth callout configuration |
|
||||
| JSLimitOpts struct | opts.go:289 | MISSING | — | Per-account JetStream limit options |
|
||||
| AuthCallout struct | opts.go:308 | PORTED | src/NATS.Server/NatsOptions.cs:234 | Added auth callout DTO (`Issuer`, `Account`, `AuthUsers`, `XKey`, `AllowedAccounts`) |
|
||||
| JSLimitOpts struct | opts.go:289 | PORTED | src/NATS.Server/NatsOptions.cs:222 | Added JetStream account limit DTO fields used by options parity |
|
||||
| JSTpmOpts struct | opts.go:300 | NOT_APPLICABLE | — | TPM (Trusted Platform Module) not applicable to .NET |
|
||||
| ProxiesConfig struct | opts.go:832 | MISSING | — | Proxy configuration |
|
||||
| ProxiesConfig struct | opts.go:832 | PORTED | src/NATS.Server/NatsOptions.cs:243 | Added proxy configuration DTO (`ProxiesConfig.Trusted` + `ProxyConfig.Key`) |
|
||||
| PinnedCertSet type | opts.go:59 | PORTED | src/NATS.Server/NatsOptions.cs:106 (TlsPinnedCerts HashSet) | — |
|
||||
| **golang/nats-server/server/opts.go — Exported Functions** | | | | |
|
||||
| ProcessConfigFile() | opts.go:870 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs:15 | Full config file parsing |
|
||||
| ConfigureOptions() | opts.go:6023 | PORTED | src/NATS.Server.Host/Program.cs:25-137 | CLI flag parsing inline |
|
||||
| MergeOptions() | opts.go:5714 | PORTED | src/NATS.Server/Configuration/ConfigReloader.cs MergeCliOverrides | — |
|
||||
| RoutesFromStr() | opts.go:5797 | MISSING | — | Parse comma-separated route URLs |
|
||||
| RoutesFromStr() | opts.go:5797 | PORTED | src/NATS.Server/NatsOptions.cs:151 | Added parser for comma-delimited route URL strings with trimming and URI validation |
|
||||
| GenTLSConfig() | opts.go:5633 | PARTIAL | src/NATS.Server/Tls/ | TLS setup exists but not as a standalone GenTLSConfig function |
|
||||
| PrintTLSHelpAndDie() | opts.go:4886 | NOT_APPLICABLE | — | Go-specific CLI help |
|
||||
| NoErrOnUnknownFields() | opts.go:50 | MISSING | — | Config parsing error control |
|
||||
| NoErrOnUnknownFields() | opts.go:50 | PORTED | src/NATS.Server/NatsOptions.cs:144 | Added global toggle used by config parser to suppress unknown top-level field failures |
|
||||
| **golang/nats-server/server/opts.go — Exported Options Methods** | | | | |
|
||||
| (o) Clone() | opts.go:715 | MISSING | — | Deep copy of Options not implemented |
|
||||
| (o) Clone() | opts.go:715 | PORTED | src/NATS.Server/NatsOptions.cs:166 | Added deep-copy clone behavior for common collections and pinned cert set |
|
||||
| (o) ProcessConfigFile() | opts.go:974 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs:17 | — |
|
||||
| (o) ProcessConfigString() | opts.go:990 | MISSING | — | Parse config from string |
|
||||
| (o) ConfigDigest() | opts.go:1000 | MISSING | — | Config file digest |
|
||||
| (o) ProcessConfigString() | opts.go:990 | PORTED | src/NATS.Server/NatsOptions.cs:196 | Added in-memory config parse/apply path and digest computation |
|
||||
| (o) ConfigDigest() | opts.go:1000 | PORTED | src/NATS.Server/NatsOptions.cs:203 | Added SHA-256-based config digest accessor |
|
||||
| **golang/nats-server/server/reload.go** | | | | |
|
||||
| FlagSnapshot var | reload.go:36 | PORTED | src/NATS.Server/NatsServer.cs:44-46 (_cliSnapshot, _cliFlags) | — |
|
||||
| option interface | reload.go:43 | PORTED | src/NATS.Server/Configuration/IConfigChange.cs | IConfigChange with Apply, IsLoggingChange, etc. |
|
||||
@@ -350,9 +350,9 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Status | Count |
|
||||
|--------|-------|
|
||||
| PORTED | 123 |
|
||||
| PARTIAL | 30 |
|
||||
| MISSING | 55 |
|
||||
| PORTED | 165 |
|
||||
| PARTIAL | 19 |
|
||||
| MISSING | 24 |
|
||||
| NOT_APPLICABLE | 14 |
|
||||
| DEFERRED | 0 |
|
||||
| **Total** | **222** |
|
||||
@@ -382,5 +382,9 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Executed core-server batch 4 parity closures: added `ActivePeers`, `StartProfiler`, `DisconnectClientByID`, `LDMClientByID`, `PortsInfo`, `UpdateServerINFOAndSendINFOToClients`, `GetConnectURLs`, and `GetNonLocalIPsIfHostIsIPAny` with targeted tests in `CoreServerGapParityTests`. | codex |
|
||||
| 2026-02-26 | Reclassified core server PID/ports-file parity rows: validated existing startup/shutdown PID and `.ports` file lifecycle implementation and updated `logPid`/`portFile` status to PORTED; refreshed `logPorts` residual note. | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Gap inventory populated: 222 symbols analyzed (123 PORTED, 30 PARTIAL, 55 MISSING, 14 NOT_APPLICABLE) across server.go, client.go, opts.go, reload.go, signal.go, service.go, main.go | claude-opus |
|
||||
| 2026-02-25 | Executed core-server batch 1 parity closures: added dedicated server URL/address/account-count/config-time/string helpers with targeted unit tests (`CoreServerGapParityTests`), and reclassified 14 rows (9 MISSING + 5 PARTIAL) to PORTED | codex |
|
||||
| 2026-02-25 | Executed core-server batch 3 options parity closures: added `Ports`, `CompressionModes`, `CompressionOpts`, `RoutesFromStr`, `NoErrOnUnknownFields`, `Clone`, `ProcessConfigString`, `ConfigDigest`, and DTOs (`JSLimitOpts`, `AuthCallout`, `ProxiesConfig`) with targeted tests (`CoreServerOptionsParityBatch3Tests`) | codex |
|
||||
|
||||
128
gaps/events.md
128
gaps/events.md
@@ -93,52 +93,52 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `ServerStatsMsg` | `golang/nats-server/server/events.go:150` | PORTED | `src/NATS.Server/Events/EventTypes.cs:383` | Full field parity |
|
||||
| `ConnectEventMsg` | `golang/nats-server/server/events.go:155` | PORTED | `src/NATS.Server/Events/EventTypes.cs:191` | Full field parity including schema type constant |
|
||||
| `DisconnectEventMsg` | `golang/nats-server/server/events.go:167` | PORTED | `src/NATS.Server/Events/EventTypes.cs:211` | Full field parity including schema type constant |
|
||||
| `OCSPPeerRejectEventMsg` | `golang/nats-server/server/events.go:182` | PARTIAL | `src/NATS.Server/Events/EventTypes.cs:520` | Go has `Peer certidp.CertInfo` with Subject/Issuer/Fingerprint/Raw; .NET `OcspPeerRejectEventMsg` omits the `Peer` CertInfo sub-object entirely — only Kind+Reason present |
|
||||
| `OCSPPeerChainlinkInvalidEventMsg` | `golang/nats-server/server/events.go:196` | MISSING | — | No .NET equivalent. Go struct has Link+Peer CertInfo objects. .NET has a different `OcspChainValidationEvent` that does not match the Go shape or advisory type string (`io.nats.server.advisory.v1.ocsp_peer_link_invalid`) |
|
||||
| `OCSPPeerRejectEventMsg` | `golang/nats-server/server/events.go:182` | PORTED | `src/NATS.Server/Events/EventTypes.cs:570` | Added `Peer` CertInfo payload parity (`subject`/`issuer`/`fingerprint`/`raw`) while preserving existing advisory fields |
|
||||
| `OCSPPeerChainlinkInvalidEventMsg` | `golang/nats-server/server/events.go:196` | PORTED | `src/NATS.Server/Events/EventTypes.cs:624` | Added dedicated parity DTO with `link` + `peer` cert info and matching advisory type string |
|
||||
| `AccountNumConns` | `golang/nats-server/server/events.go:210` | PORTED | `src/NATS.Server/Events/EventTypes.cs:245` | Full field parity including schema type constant |
|
||||
| `AccountStat` | `golang/nats-server/server/events.go:217` | PORTED | `src/NATS.Server/Events/EventTypes.cs:245` | Fields embedded inline in `AccountNumConns` — matches Go embedding pattern |
|
||||
| `ServerInfo` | `golang/nats-server/server/events.go:249` | PORTED | `src/NATS.Server/Events/EventTypes.cs:9` | `EventServerInfo` — all fields present; `Flags` typed as `ulong` (Go `ServerCapability uint64`) |
|
||||
| `ServerID` | `golang/nats-server/server/events.go:239` | MISSING | — | Simple struct with Name/Host/ID used in `idzReq` response; no .NET equivalent |
|
||||
| `ServerCapability` (type + consts) | `golang/nats-server/server/events.go:246` | MISSING | — | `JetStreamEnabled`, `BinaryStreamSnapshot`, `AccountNRG` capability flags; .NET has the `Flags ulong` field but no typed enum/const for capability bits |
|
||||
| `ServerID` | `golang/nats-server/server/events.go:239` | PORTED | `src/NATS.Server/Events/EventTypes.cs:22` | Added `ServerID` DTO with `name`/`host`/`id` JSON fields for IDZ-style responses |
|
||||
| `ServerCapability` (type + consts) | `golang/nats-server/server/events.go:246` | PORTED | `src/NATS.Server/Events/EventTypes.cs:10` | Added `[Flags] ServerCapability` enum with `JetStreamEnabled`, `BinaryStreamSnapshot`, and `AccountNRG` bits |
|
||||
| `ClientInfo` | `golang/nats-server/server/events.go:308` | PORTED | `src/NATS.Server/Events/EventTypes.cs:62` | `EventClientInfo` — all fields present; RTT stored as `long RttNanos` vs Go `time.Duration` |
|
||||
| `ServerStats` | `golang/nats-server/server/events.go:364` | PORTED | `src/NATS.Server/Events/EventTypes.cs:395` | `ServerStatsData` — full field parity; .NET adds `InMsgs/OutMsgs/InBytes/OutBytes` compat fields not in Go (extra, not missing) |
|
||||
| `RouteStat` | `golang/nats-server/server/events.go:390` | PORTED | `src/NATS.Server/Events/EventTypes.cs:303` | Full field parity |
|
||||
| `GatewayStat` | `golang/nats-server/server/events.go:398` | PORTED | `src/NATS.Server/Events/EventTypes.cs:326` | Full field parity |
|
||||
| `MsgBytes` | `golang/nats-server/server/events.go:407` | PORTED | `src/NATS.Server/Events/EventTypes.cs:181` | `MsgBytesStats` — same fields |
|
||||
| `DataStats` | `golang/nats-server/server/events.go:412` | PORTED | `src/NATS.Server/Events/EventTypes.cs:156` | Full field parity |
|
||||
| `EventFilterOptions` | `golang/nats-server/server/events.go:1946` | MISSING | — | No .NET equivalent; used for server-side request filtering by name/cluster/host/tags/domain |
|
||||
| `StatszEventOptions` | `golang/nats-server/server/events.go:1956` | MISSING | — | No .NET equivalent |
|
||||
| `AccInfoEventOptions` | `golang/nats-server/server/events.go:1962` | MISSING | — | No .NET equivalent |
|
||||
| `ConnzEventOptions` | `golang/nats-server/server/events.go:1968` | MISSING | — | No .NET equivalent |
|
||||
| `RoutezEventOptions` | `golang/nats-server/server/events.go:1974` | MISSING | — | No .NET equivalent |
|
||||
| `SubszEventOptions` | `golang/nats-server/server/events.go:1980` | MISSING | — | No .NET equivalent |
|
||||
| `VarzEventOptions` | `golang/nats-server/server/events.go:1986` | MISSING | — | No .NET equivalent |
|
||||
| `GatewayzEventOptions` | `golang/nats-server/server/events.go:1992` | MISSING | — | No .NET equivalent |
|
||||
| `LeafzEventOptions` | `golang/nats-server/server/events.go:1997` | MISSING | — | No .NET equivalent |
|
||||
| `AccountzEventOptions` | `golang/nats-server/server/events.go:2004` | MISSING | — | No .NET equivalent |
|
||||
| `AccountStatzEventOptions` | `golang/nats-server/server/events.go:2010` | MISSING | — | No .NET equivalent |
|
||||
| `JszEventOptions` | `golang/nats-server/server/events.go:2016` | MISSING | — | No .NET equivalent |
|
||||
| `HealthzEventOptions` | `golang/nats-server/server/events.go:2022` | MISSING | — | No .NET equivalent |
|
||||
| `ProfilezEventOptions` | `golang/nats-server/server/events.go:2028` | MISSING | — | No .NET equivalent |
|
||||
| `ExpvarzEventOptions` | `golang/nats-server/server/events.go:2034` | MISSING | — | No .NET equivalent |
|
||||
| `IpqueueszEventOptions` | `golang/nats-server/server/events.go:2039` | MISSING | — | No .NET equivalent |
|
||||
| `RaftzEventOptions` | `golang/nats-server/server/events.go:2045` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPIResponse` | `golang/nats-server/server/events.go:2092` | MISSING | — | Generic request-reply envelope; no .NET equivalent |
|
||||
| `ServerAPIConnzResponse` | `golang/nats-server/server/events.go:2106` | MISSING | — | Typed response wrappers for Z endpoints; no .NET equivalent |
|
||||
| `ServerAPIRoutezResponse` | `golang/nats-server/server/events.go:2113` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPIGatewayzResponse` | `golang/nats-server/server/events.go:2119` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPIJszResponse` | `golang/nats-server/server/events.go:2126` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPIHealthzResponse` | `golang/nats-server/server/events.go:2133` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPIVarzResponse` | `golang/nats-server/server/events.go:2141` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPISubszResponse` | `golang/nats-server/server/events.go:2148` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPILeafzResponse` | `golang/nats-server/server/events.go:2155` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPIAccountzResponse` | `golang/nats-server/server/events.go:2162` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPIExpvarzResponse` | `golang/nats-server/server/events.go:2169` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPIpqueueszResponse` | `golang/nats-server/server/events.go:2175` | MISSING | — | No .NET equivalent |
|
||||
| `ServerAPIRaftzResponse` | `golang/nats-server/server/events.go:2183` | MISSING | — | No .NET equivalent |
|
||||
| `KickClientReq` | `golang/nats-server/server/events.go:3180` | MISSING | — | No .NET equivalent |
|
||||
| `LDMClientReq` | `golang/nats-server/server/events.go:3184` | MISSING | — | No .NET equivalent |
|
||||
| `UserInfo` | `golang/nats-server/server/events.go:1500` | MISSING | — | No .NET equivalent |
|
||||
| `EventFilterOptions` | `golang/nats-server/server/events.go:1946` | PORTED | `src/NATS.Server/Events/EventTypes.cs:929` | Added shared filter DTO with name/cluster/host/tags/domain fields |
|
||||
| `StatszEventOptions` | `golang/nats-server/server/events.go:1956` | PORTED | `src/NATS.Server/Events/EventTypes.cs:952` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `AccInfoEventOptions` | `golang/nats-server/server/events.go:1962` | PORTED | `src/NATS.Server/Events/EventTypes.cs:953` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `ConnzEventOptions` | `golang/nats-server/server/events.go:1968` | PORTED | `src/NATS.Server/Events/EventTypes.cs:954` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `RoutezEventOptions` | `golang/nats-server/server/events.go:1974` | PORTED | `src/NATS.Server/Events/EventTypes.cs:955` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `SubszEventOptions` | `golang/nats-server/server/events.go:1980` | PORTED | `src/NATS.Server/Events/EventTypes.cs:956` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `VarzEventOptions` | `golang/nats-server/server/events.go:1986` | PORTED | `src/NATS.Server/Events/EventTypes.cs:957` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `GatewayzEventOptions` | `golang/nats-server/server/events.go:1992` | PORTED | `src/NATS.Server/Events/EventTypes.cs:958` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `LeafzEventOptions` | `golang/nats-server/server/events.go:1997` | PORTED | `src/NATS.Server/Events/EventTypes.cs:959` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `AccountzEventOptions` | `golang/nats-server/server/events.go:2004` | PORTED | `src/NATS.Server/Events/EventTypes.cs:960` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `AccountStatzEventOptions` | `golang/nats-server/server/events.go:2010` | PORTED | `src/NATS.Server/Events/EventTypes.cs:961` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `JszEventOptions` | `golang/nats-server/server/events.go:2016` | PORTED | `src/NATS.Server/Events/EventTypes.cs:962` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `HealthzEventOptions` | `golang/nats-server/server/events.go:2022` | PORTED | `src/NATS.Server/Events/EventTypes.cs:963` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `ProfilezEventOptions` | `golang/nats-server/server/events.go:2028` | PORTED | `src/NATS.Server/Events/EventTypes.cs:964` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `ExpvarzEventOptions` | `golang/nats-server/server/events.go:2034` | PORTED | `src/NATS.Server/Events/EventTypes.cs:965` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `IpqueueszEventOptions` | `golang/nats-server/server/events.go:2039` | PORTED | `src/NATS.Server/Events/EventTypes.cs:966` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `RaftzEventOptions` | `golang/nats-server/server/events.go:2045` | PORTED | `src/NATS.Server/Events/EventTypes.cs:967` | Added typed options wrapper inheriting `EventFilterOptions` |
|
||||
| `ServerAPIResponse` | `golang/nats-server/server/events.go:2092` | PORTED | `src/NATS.Server/Events/EventTypes.cs:988` | Added generic request/reply envelope with `server`, `data`, and `error` payload |
|
||||
| `ServerAPIConnzResponse` | `golang/nats-server/server/events.go:2106` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1003` | Added typed server API response wrapper |
|
||||
| `ServerAPIRoutezResponse` | `golang/nats-server/server/events.go:2113` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1004` | Added typed server API response wrapper |
|
||||
| `ServerAPIGatewayzResponse` | `golang/nats-server/server/events.go:2119` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1005` | Added typed server API response wrapper |
|
||||
| `ServerAPIJszResponse` | `golang/nats-server/server/events.go:2126` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1006` | Added typed server API response wrapper |
|
||||
| `ServerAPIHealthzResponse` | `golang/nats-server/server/events.go:2133` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1007` | Added typed server API response wrapper |
|
||||
| `ServerAPIVarzResponse` | `golang/nats-server/server/events.go:2141` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1008` | Added typed server API response wrapper |
|
||||
| `ServerAPISubszResponse` | `golang/nats-server/server/events.go:2148` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1009` | Added typed server API response wrapper |
|
||||
| `ServerAPILeafzResponse` | `golang/nats-server/server/events.go:2155` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1010` | Added typed server API response wrapper |
|
||||
| `ServerAPIAccountzResponse` | `golang/nats-server/server/events.go:2162` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1011` | Added typed server API response wrapper |
|
||||
| `ServerAPIExpvarzResponse` | `golang/nats-server/server/events.go:2169` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1012` | Added typed server API response wrapper |
|
||||
| `ServerAPIpqueueszResponse` | `golang/nats-server/server/events.go:2175` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1013` | Added typed server API response wrapper |
|
||||
| `ServerAPIRaftzResponse` | `golang/nats-server/server/events.go:2183` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1014` | Added typed server API response wrapper |
|
||||
| `KickClientReq` | `golang/nats-server/server/events.go:3180` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1020` | Added request DTO with `cid` payload field |
|
||||
| `LDMClientReq` | `golang/nats-server/server/events.go:3184` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1030` | Added request DTO with `cid` payload field |
|
||||
| `UserInfo` | `golang/nats-server/server/events.go:1500` | PORTED | `src/NATS.Server/Events/EventTypes.cs:1040` | Added direct user info DTO with user/account/permissions fields |
|
||||
| `SlowConsumersStats` | `golang/nats-server/server/events.go:377` | PORTED | `src/NATS.Server/Events/EventTypes.cs:344` | Full field parity |
|
||||
| `StaleConnectionStats` | `golang/nats-server/server/events.go:379` | PORTED | `src/NATS.Server/Events/EventTypes.cs:363` | Full field parity |
|
||||
|
||||
@@ -152,20 +152,20 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `sysMsgHandler` type | `golang/nats-server/server/events.go:109` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:67` | `SystemMessageHandler` delegate — same signature shape |
|
||||
| `serverUpdate` struct | `golang/nats-server/server/events.go:461` | MISSING | — | Tracks seq + ltime for remote server heartbeat ordering; no .NET equivalent |
|
||||
| `accNumConnsReq` struct | `golang/nats-server/server/events.go:233` | PORTED | `src/NATS.Server/Events/EventTypes.cs:797` | `AccNumConnsReq` — full field parity |
|
||||
| `accNumSubsReq` struct | `golang/nats-server/server/events.go:2966` | MISSING | — | Used for debug subscriber count requests; no .NET equivalent |
|
||||
| `compressionType` + consts | `golang/nats-server/server/events.go:2082` | PARTIAL | `src/NATS.Server/Events/EventCompressor.cs` | `EventCompressor` handles snappy compression; no gzip compression path; `compressionType` enum itself not present as typed enum — only Snappy supported |
|
||||
| `accNumSubsReq` struct | `golang/nats-server/server/events.go:2966` | PORTED | `src/NATS.Server/Events/EventTypes.cs:916` | Added account subscription-count request DTO with server + account fields |
|
||||
| `compressionType` + consts | `golang/nats-server/server/events.go:2082` | PORTED | `src/NATS.Server/Events/EventCompressor.cs:13` | Added `EventCompressionType` enum with `None`, `Gzip`, `Snappy`, and `Unsupported`; compressor now supports both Snappy and Gzip encode/decode paths. |
|
||||
| `msgHandler` type | `golang/nats-server/server/events.go:2751` | NOT_APPLICABLE | — | Go internal callback type merging header+body bytes; .NET uses the `SystemMessageHandler` delegate with separate header/body params |
|
||||
|
||||
### events.go — Exported Methods on ServerInfo
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `(*ServerInfo).SetJetStreamEnabled()` | `golang/nats-server/server/events.go:274` | MISSING | — | No .NET method; `EventServerInfo` has the raw `Flags` field but no typed capability methods |
|
||||
| `(*ServerInfo).JetStreamEnabled()` bool | `golang/nats-server/server/events.go:281` | MISSING | — | No .NET equivalent |
|
||||
| `(*ServerInfo).SetBinaryStreamSnapshot()` | `golang/nats-server/server/events.go:287` | MISSING | — | No .NET equivalent |
|
||||
| `(*ServerInfo).BinaryStreamSnapshot()` bool | `golang/nats-server/server/events.go:292` | MISSING | — | No .NET equivalent |
|
||||
| `(*ServerInfo).SetAccountNRG()` | `golang/nats-server/server/events.go:297` | MISSING | — | No .NET equivalent |
|
||||
| `(*ServerInfo).AccountNRG()` bool | `golang/nats-server/server/events.go:302` | MISSING | — | No .NET equivalent |
|
||||
| `(*ServerInfo).SetJetStreamEnabled()` | `golang/nats-server/server/events.go:274` | PORTED | `src/NATS.Server/Events/EventTypes.cs:86` | Added helper to set `JetStream` and capability flag atomically for parity |
|
||||
| `(*ServerInfo).JetStreamEnabled()` bool | `golang/nats-server/server/events.go:281` | PORTED | `src/NATS.Server/Events/EventTypes.cs:92` | Added flag-check helper using typed `ServerCapability.JetStreamEnabled` |
|
||||
| `(*ServerInfo).SetBinaryStreamSnapshot()` | `golang/nats-server/server/events.go:287` | PORTED | `src/NATS.Server/Events/EventTypes.cs:95` | Added capability setter for binary stream snapshot support |
|
||||
| `(*ServerInfo).BinaryStreamSnapshot()` bool | `golang/nats-server/server/events.go:292` | PORTED | `src/NATS.Server/Events/EventTypes.cs:98` | Added capability getter for binary stream snapshot support |
|
||||
| `(*ServerInfo).SetAccountNRG()` | `golang/nats-server/server/events.go:297` | PORTED | `src/NATS.Server/Events/EventTypes.cs:101` | Added capability setter for account NRG support |
|
||||
| `(*ServerInfo).AccountNRG()` bool | `golang/nats-server/server/events.go:302` | PORTED | `src/NATS.Server/Events/EventTypes.cs:104` | Added capability getter for account NRG support |
|
||||
|
||||
### events.go — Unexported Methods on ClientInfo
|
||||
|
||||
@@ -205,8 +205,8 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `(*Server).sendAccConnsUpdate()` | `golang/nats-server/server/events.go:2407` | MISSING | — | No .NET equivalent |
|
||||
| `(*Server).accConnsUpdate()` | `golang/nats-server/server/events.go:2506` | MISSING | — | No .NET equivalent |
|
||||
| `(*Server).nextEventID()` | `golang/nats-server/server/events.go:2516` | PARTIAL | `src/NATS.Server/Events/EventTypes.cs:943` | `EventBuilder.GenerateEventId()` uses `Guid.NewGuid()`; Go uses nuid (faster nano-ID generator) |
|
||||
| `(*Server).accountConnectEvent()` | `golang/nats-server/server/events.go:2522` | PARTIAL | `src/NATS.Server/Events/InternalEventSystem.cs:303` | `SendConnectEvent()` exists; missing: JWT/IssuerKey/Tags/NameTag/Kind/ClientType/MQTTClientID fields in ConnectEventDetail |
|
||||
| `(*Server).accountDisconnectEvent()` | `golang/nats-server/server/events.go:2569` | PARTIAL | `src/NATS.Server/Events/InternalEventSystem.cs:329` | `SendDisconnectEvent()` exists; missing: RTT/JWT/IssuerKey/Tags/NameTag/Kind/ClientType/MQTTClientID fields in DisconnectEventDetail |
|
||||
| `(*Server).accountConnectEvent()` | `golang/nats-server/server/events.go:2522` | PORTED | `src/NATS.Server/Events/InternalEventSystem.cs:322` | Extended `ConnectEventDetail` and event mapping to include JWT/issuer/tags/name-tag/kind/client-type/MQTT client id parity fields |
|
||||
| `(*Server).accountDisconnectEvent()` | `golang/nats-server/server/events.go:2569` | PORTED | `src/NATS.Server/Events/InternalEventSystem.cs:355` | Extended `DisconnectEventDetail` and event mapping to include RTT + JWT/issuer/tags/name-tag/kind/client-type/MQTT client id parity fields |
|
||||
| `(*Server).sendAuthErrorEvent()` | `golang/nats-server/server/events.go:2631` | PARTIAL | `src/NATS.Server/Events/InternalEventSystem.cs:277` | `SendAuthErrorEvent()` exists; Go uses `DisconnectEventMsg` shape for auth errors (surprising but correct); .NET uses `AuthErrorEventMsg` with different schema type |
|
||||
| `(*Server).sendAccountAuthErrorEvent()` | `golang/nats-server/server/events.go:2690` | MISSING | — | Account-level auth error event to account subject; no .NET equivalent |
|
||||
| `(*Server).sendOCSPPeerRejectEvent()` | `golang/nats-server/server/events.go:3267` | PARTIAL | `src/NATS.Server/Events/EventTypes.cs:612` | `OcspEventBuilder.BuildPeerReject()` helper exists; no publishing method on server; missing `Peer` CertInfo payload |
|
||||
@@ -257,7 +257,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `getHash()` | `golang/nats-server/server/events.go:1141` | PORTED | `src/NATS.Server/Events/InternalEventSystem.cs:118` | SHA-256 8-char hash; same algorithm |
|
||||
| `getHashSize()` | `golang/nats-server/server/events.go:1146` | MISSING | — | Parameterized size variant; only 8-char version ported |
|
||||
| `getHashSize()` | `golang/nats-server/server/events.go:1146` | PORTED | `src/NATS.Server/Events/InternalEventSystem.cs:143` | Added `GetHashSize()` and size-aware `GetHash(string, int)` helpers; constructor now uses them for server hash generation |
|
||||
| `routeStat()` | `golang/nats-server/server/events.go:859` | NOT_APPLICABLE | — | Route stat collection; clustering not yet ported |
|
||||
| `newPubMsg()` | `golang/nats-server/server/events.go:435` | NOT_APPLICABLE | — | Pool-based pubMsg factory; .NET uses `PublishMessage` record without pooling |
|
||||
| `(*pubMsg).returnToPool()` | `golang/nats-server/server/events.go:452` | NOT_APPLICABLE | — | Pool return; .NET has no pool |
|
||||
@@ -266,7 +266,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `clearTimer()` | `golang/nats-server/server/events.go:3244` | NOT_APPLICABLE | — | Go timer management idiom; .NET uses `PeriodicTimer` / `CancellationToken` |
|
||||
| `totalSubs()` | `golang/nats-server/server/events.go:2973` | MISSING | — | No .NET equivalent |
|
||||
| `remoteLatencySubjectForResponse()` | `golang/nats-server/server/events.go:2860` | NOT_APPLICABLE | — | Latency tracking; not yet ported |
|
||||
| `getAcceptEncoding()` | `golang/nats-server/server/events.go:2238` | MISSING | — | Parses Accept-Encoding header for compression type; no .NET equivalent |
|
||||
| `getAcceptEncoding()` | `golang/nats-server/server/events.go:2238` | PORTED | `src/NATS.Server/Events/EventCompressor.cs:192` | Added `EventCompressor.GetAcceptEncoding(string?)` parser: prefers `snappy`/`s2`, falls back to `gzip`, otherwise `unsupported`, matching Go behavior. |
|
||||
| `(*Account).statz()` | `golang/nats-server/server/events.go:2446` | NOT_APPLICABLE | — | Account stats snapshot; Account class not yet in Events module |
|
||||
|
||||
### events.go — Constants / Subjects
|
||||
@@ -286,27 +286,27 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `serverPingReqSubj` | `golang/nats-server/server/events.go:68` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:35` | `ServerPing` — matching |
|
||||
| `accDirectReqSubj` | `golang/nats-server/server/events.go:51` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:38` | `AccountReq` — matching |
|
||||
| `inboxRespSubj` | `golang/nats-server/server/events.go:73` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:41` | `InboxResponse` — matching |
|
||||
| `ocspPeerRejectEventSubj` | `golang/nats-server/server/events.go:95` | PARTIAL | `src/NATS.Server/Events/EventSubjects.cs:45` | Go: `$SYS.SERVER.%s.OCSP.PEER.CONN.REJECT`; .NET: `$SYS.SERVER.{0}.OCSP.PEER.REJECT` — different path segment |
|
||||
| `ocspPeerChainlinkInvalidEventSubj` | `golang/nats-server/server/events.go:96` | MISSING | — | Go: `$SYS.SERVER.%s.OCSP.PEER.LINK.INVALID`; .NET `OcspChainValidation` uses `$SYS.SERVER.{0}.OCSP.CHAIN.VALIDATION` — different subject |
|
||||
| `leafNodeConnectEventSubj` | `golang/nats-server/server/events.go:71` | PARTIAL | `src/NATS.Server/Events/EventSubjects.cs:28` | .NET subject `$SYS.SERVER.{0}.LEAFNODE.CONNECT` differs from Go `$SYS.ACCOUNT.%s.LEAFNODE.CONNECT` |
|
||||
| `remoteLatencyEventSubj` | `golang/nats-server/server/events.go:72` | MISSING | — | No .NET equivalent |
|
||||
| `userDirectInfoSubj` | `golang/nats-server/server/events.go:76` | MISSING | — | No .NET equivalent |
|
||||
| `userDirectReqSubj` | `golang/nats-server/server/events.go:77` | MISSING | — | No .NET equivalent |
|
||||
| `accNumSubsReqSubj` | `golang/nats-server/server/events.go:81` | MISSING | — | No .NET equivalent |
|
||||
| `accSubsSubj` | `golang/nats-server/server/events.go:84` | MISSING | — | No .NET equivalent |
|
||||
| `clientKickReqSubj` | `golang/nats-server/server/events.go:62` | MISSING | — | No .NET equivalent |
|
||||
| `clientLDMReqSubj` | `golang/nats-server/server/events.go:63` | MISSING | — | No .NET equivalent |
|
||||
| `serverStatsPingReqSubj` | `golang/nats-server/server/events.go:69` | MISSING | — | No .NET equivalent |
|
||||
| `serverReloadReqSubj` | `golang/nats-server/server/events.go:70` | MISSING | — | No .NET equivalent |
|
||||
| `ocspPeerRejectEventSubj` | `golang/nats-server/server/events.go:95` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:54` | Corrected to `$SYS.SERVER.{0}.OCSP.PEER.CONN.REJECT` |
|
||||
| `ocspPeerChainlinkInvalidEventSubj` | `golang/nats-server/server/events.go:96` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:55` | Added `$SYS.SERVER.{0}.OCSP.PEER.LINK.INVALID` subject constant |
|
||||
| `leafNodeConnectEventSubj` | `golang/nats-server/server/events.go:71` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:28` | Corrected to account-scoped subject `$SYS.ACCOUNT.{0}.LEAFNODE.CONNECT` |
|
||||
| `remoteLatencyEventSubj` | `golang/nats-server/server/events.go:72` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:30` | Added remote latency response subject constant |
|
||||
| `userDirectInfoSubj` | `golang/nats-server/server/events.go:76` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:40` | Added user info request subject constant |
|
||||
| `userDirectReqSubj` | `golang/nats-server/server/events.go:77` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:41` | Added per-user direct info request subject constant |
|
||||
| `accNumSubsReqSubj` | `golang/nats-server/server/events.go:81` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:42` | Added account subscription-count request subject constant |
|
||||
| `accSubsSubj` | `golang/nats-server/server/events.go:84` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:43` | Added account subscription-count response subject constant |
|
||||
| `clientKickReqSubj` | `golang/nats-server/server/events.go:62` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:44` | Added kick-client request subject constant |
|
||||
| `clientLDMReqSubj` | `golang/nats-server/server/events.go:63` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:45` | Added lame-duck-mode client request subject constant |
|
||||
| `serverStatsPingReqSubj` | `golang/nats-server/server/events.go:69` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:46` | Added wildcard statsz ping request subject constant |
|
||||
| `serverReloadReqSubj` | `golang/nats-server/server/events.go:70` | PORTED | `src/NATS.Server/Events/EventSubjects.cs:47` | Added server reload request subject constant |
|
||||
| `accPingReqSubj` | `golang/nats-server/server/events.go:52` | MISSING | — | No .NET equivalent |
|
||||
| `connsRespSubj` | `golang/nats-server/server/events.go:57` | MISSING | — | No .NET equivalent |
|
||||
| `accLookupReqSubj` / JWT subjects | `golang/nats-server/server/events.go:43` | NOT_APPLICABLE | — | JWT operator resolver subjects; not yet ported |
|
||||
| `InboxPrefix` | `golang/nats-server/server/events.go:2946` | MISSING | — | No .NET equivalent |
|
||||
| `acceptEncodingHeader` / `contentEncodingHeader` | `golang/nats-server/server/events.go:2232` | MISSING | — | Header name constants for compression negotiation; no .NET equivalent |
|
||||
| `acceptEncodingHeader` / `contentEncodingHeader` | `golang/nats-server/server/events.go:2232` | PORTED | `src/NATS.Server/Events/EventCompressor.cs:28` | Added `AcceptEncodingHeader` and `ContentEncodingHeader` constants for compression negotiation headers. |
|
||||
| `ConnectEventMsgType` | `golang/nats-server/server/events.go:163` | PORTED | `src/NATS.Server/Events/EventTypes.cs:193` | `ConnectEventMsg.EventType` constant — matching value |
|
||||
| `DisconnectEventMsgType` | `golang/nats-server/server/events.go:177` | PORTED | `src/NATS.Server/Events/EventTypes.cs:214` | `DisconnectEventMsg.EventType` — matching value |
|
||||
| `OCSPPeerRejectEventMsgType` | `golang/nats-server/server/events.go:191` | PORTED | `src/NATS.Server/Events/EventTypes.cs:522` | `OcspPeerRejectEventMsg.EventType` — matching value |
|
||||
| `OCSPPeerChainlinkInvalidEventMsgType` | `golang/nats-server/server/events.go:205` | MISSING | — | No .NET equivalent with matching type string `io.nats.server.advisory.v1.ocsp_peer_link_invalid` |
|
||||
| `OCSPPeerChainlinkInvalidEventMsgType` | `golang/nats-server/server/events.go:205` | PORTED | `src/NATS.Server/Events/EventTypes.cs:626` | Added `OcspPeerChainlinkInvalidEventMsg.EventType` constant with matching advisory type |
|
||||
| `AccountNumConnsMsgType` | `golang/nats-server/server/events.go:229` | PORTED | `src/NATS.Server/Events/EventTypes.cs:247` | `AccountNumConns.EventType` — matching value |
|
||||
|
||||
---
|
||||
@@ -406,5 +406,7 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Ported events compression parity helpers: added typed compression enum, gzip/snappy encode-decode support, Accept-Encoding parser, and header-name constants with focused events compression tests. | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Full gap inventory populated from Go source analysis | auto |
|
||||
| 2026-02-25 | Ported Events API option DTOs, server API response wrappers, OCSP peer/link advisory payloads, missing request subjects, account connect/disconnect parity fields, and hash-size helpers; validated with focused Events tests | codex |
|
||||
|
||||
90
gaps/execution.md
Normal file
90
gaps/execution.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Category Execution Instructions
|
||||
|
||||
Use this runbook to execute one category end-to-end using the `executeplan` skill without running the full test suite.
|
||||
|
||||
## Inputs
|
||||
- `CATEGORY` (example: `protocol`)
|
||||
- `gaps/plans.md` row for that category (contains category gap file, design file, and plan file paths)
|
||||
|
||||
## Required Skills
|
||||
- `executeplan`
|
||||
- `using-git-worktrees` (required before implementation)
|
||||
- `finishing-a-development-branch` (required after implementation)
|
||||
|
||||
## Execution Flow
|
||||
1. Resolve the category row from `gaps/plans.md`.
|
||||
2. Read the category's design and plan files from the resolved row.
|
||||
3. Announce: `I'm using executeplan to implement this plan.`
|
||||
4. Create a brand-new git worktree on a new branch and verify clean status.
|
||||
5. Execute the plan in batches (`executeplan` default batching), with checkpoints between batches.
|
||||
6. Run only targeted unit tests for the category after each batch; do not run full-suite tests.
|
||||
7. After implementation, verify the category gap file reflects the completed work.
|
||||
8. Update the `Status` column in `gaps/plans.md` for the category:
|
||||
- `complete` if no `MISSING` or `PARTIAL` rows remain
|
||||
- `<N> remaining` where `N = MISSING + PARTIAL`
|
||||
|
||||
## Strict Test Scope Policy
|
||||
- Never run unscoped full test commands such as:
|
||||
- `dotnet test tests/NATS.Server.Tests/NATS.Server.Tests.csproj`
|
||||
- Always use targeted test execution, for example:
|
||||
- `dotnet test tests/NATS.Server.Tests/NATS.Server.Tests.csproj --filter "FullyQualifiedName~Protocol"`
|
||||
- `dotnet test tests/NATS.Server.Tests/NATS.Server.Tests.csproj --filter "FullyQualifiedName~JetStream"`
|
||||
- `dotnet test tests/NATS.Server.Tests/NATS.Server.Tests.csproj --filter "FullyQualifiedName~Auth"`
|
||||
- If one filter is too broad, split into multiple narrow filters and run them separately.
|
||||
|
||||
## Suggested Category Filter Tokens
|
||||
Use these as starting points for `--filter "FullyQualifiedName~<token>"`:
|
||||
|
||||
| Category | Token(s) |
|
||||
|---|---|
|
||||
| `core-server` | `Server`, `Client` |
|
||||
| `protocol` | `Protocol`, `Parser` |
|
||||
| `subscriptions` | `Subscription` |
|
||||
| `auth-and-accounts` | `Auth`, `Account` |
|
||||
| `configuration` | `Configuration`, `Config` |
|
||||
| `routes` | `Route` |
|
||||
| `gateways` | `Gateway` |
|
||||
| `leaf-nodes` | `Leaf` |
|
||||
| `jetstream` | `JetStream` |
|
||||
| `raft` | `Raft` |
|
||||
| `mqtt` | `Mqtt` |
|
||||
| `websocket` | `WebSocket` |
|
||||
| `monitoring` | `Monitoring` |
|
||||
| `events` | `Event` |
|
||||
| `tls-security` | `Tls`, `Security` |
|
||||
| `internal-ds` | `Internal` |
|
||||
| `logging` | `Log`, `Logging` |
|
||||
| `utilities-and-other` | `IO`, `Server` |
|
||||
| `misc-uncategorized` | `Misc`, `Server` |
|
||||
|
||||
## Gap Verification Rules (Category Gap File)
|
||||
For the category gap file (`gaps/<category>.md`):
|
||||
1. Every implemented item must be updated in the Gap Inventory.
|
||||
2. Each newly completed row must include:
|
||||
- `Status = PORTED`
|
||||
- concrete `.NET Equivalent` file:line
|
||||
- concise notes for parity behavior
|
||||
3. If behavior is still partial, keep `PARTIAL` and document what is still missing.
|
||||
4. Do not mark `complete` in `gaps/plans.md` until both `MISSING` and `PARTIAL` counts are zero.
|
||||
|
||||
## Status Update Command Snippet
|
||||
After finishing a category, compute remaining gaps:
|
||||
|
||||
```bash
|
||||
remaining=$(awk -F'|' '
|
||||
NF >= 4 {
|
||||
s=$4
|
||||
gsub(/^ +| +$/, "", s)
|
||||
if (s=="MISSING" || s=="PARTIAL") c++
|
||||
}
|
||||
END { print c+0 }
|
||||
' "gaps/${CATEGORY}.md")
|
||||
|
||||
if [ "$remaining" -eq 0 ]; then
|
||||
status_value="complete"
|
||||
else
|
||||
status_value="${remaining} remaining"
|
||||
fi
|
||||
```
|
||||
|
||||
Then write `status_value` into that category row in `gaps/plans.md`.
|
||||
@@ -94,9 +94,9 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `GatewayDoNotForceInterestOnlyMode` | gateway.go:130 | NOT_APPLICABLE | — | Test-only global flag; disables forced interest-only mode in tests. Go-specific test hook. |
|
||||
| `GatewayInterestMode` (enum: Optimistic/Transitioning/InterestOnly) | gateway.go:94–111 | PORTED | `src/NATS.Server/Gateways/GatewayInterestTracker.cs:16` | `GatewayInterestMode` enum with identical three values. |
|
||||
| `GatewayInterestMode.String()` | gateway.go:113 | NOT_APPLICABLE | — | Go stringer pattern; C# uses `ToString()` automatically. |
|
||||
| `gwReplyPrefix` / `gwReplyPrefixLen` / `gwHashLen` / offset constants | gateway.go:49–58 | PARTIAL | `src/NATS.Server/Gateways/ReplyMapper.cs:12` | `GatewayReplyPrefix = "_GR_."` is present. Hash length and byte-offset arithmetic constants are missing; .NET uses string-segment parsing instead of fixed-width offsets. |
|
||||
| `oldGWReplyPrefix` / `oldGWReplyPrefixLen` / `oldGWReplyStart` | gateway.go:43–46 | MISSING | — | Old `$GR.` reply prefix for backward-compat with pre-v2.9 servers is not represented in .NET. `ReplyMapper.TryRestoreGatewayReply` handles it partially via numeric-hash detection but has no dedicated constant. |
|
||||
| `gatewayTLSInsecureWarning` | gateway.go:71 | MISSING | — | TLS insecure warning string; no TLS gateway support yet. |
|
||||
| `gwReplyPrefix` / `gwReplyPrefixLen` / `gwHashLen` / offset constants | gateway.go:49–58 | PORTED | `src/NATS.Server/Gateways/ReplyMapper.cs:12–17` | Reply-prefix/length/hash-length constants are explicitly defined (`GatewayReplyPrefix`, `GatewayReplyPrefixLen`, `GatewayHashLen`, plus legacy counterparts). |
|
||||
| `oldGWReplyPrefix` / `oldGWReplyPrefixLen` / `oldGWReplyStart` | gateway.go:43–46 | PORTED | `src/NATS.Server/Gateways/ReplyMapper.cs:13,15,31` | Legacy `$GR.` prefix constants and old-prefix detection are implemented via `IsGatewayRoutedSubject(..., out isOldPrefix)`. |
|
||||
| `gatewayTLSInsecureWarning` | gateway.go:71 | PORTED | `src/NATS.Server/Gateways/GatewayManager.cs:68` | Gateway TLS insecure warning constant is defined for parity/documentation and diagnostic use. |
|
||||
|
||||
#### Structs / Types
|
||||
|
||||
@@ -104,7 +104,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `srvGateway` struct | gateway.go:134 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:66` | `GatewayManager` covers outbound/inbound maps, accept loop, discovery, registration, and stats. Missing: RTT-ordered outbound list (`outo`), `totalQSubs` atomic counter, `pasi` per-account subscription interest map, `rsubs` recent-subscription sync.Map, `sIDHash`/`routesIDByHash` for reply routing, `sqbsz`/`recSubExp`, and `oldHash`/`oldReplyPfx` for backward compat. |
|
||||
| `sitally` struct | gateway.go:189 | MISSING | — | Subject-interest tally (ref count + queue flag) used in `pasi.m`. No equivalent in .NET. |
|
||||
| `gatewayCfg` struct | gateway.go:194 | PARTIAL | `src/NATS.Server/Configuration/GatewayOptions.cs:27` (`RemoteGatewayOptions`) | `RemoteGatewayOptions` covers name and URLs. Missing: `hash`/`oldHash` byte arrays, `implicit` flag, `connAttempts` counter, `tlsName`, `varzUpdateURLs`, URL management methods (`addURLs`, `updateURLs`, `getURLs`, `saveTLSHostname`), and per-remote TLS config. |
|
||||
| `gatewayCfg` struct | gateway.go:194 | PARTIAL | `src/NATS.Server/Configuration/GatewayOptions.cs:27` (`RemoteGatewayOptions`) | Added parity state and helpers for `hash`/`oldHash`, `implicit`, connection attempts, TLS host capture, URL add/update/get flows, and varz URL-update flag. Remaining gap: per-remote TLS config wiring into active gateway dial/handshake path. |
|
||||
| `gateway` struct (per-client) | gateway.go:207 | MISSING | — | Per-connection gateway state (outbound flag, `outsim` sync.Map, `insim` map, `connectURL`, `useOldPrefix`, `interestOnlyMode`, `remoteName`). Absorbed into `GatewayConnection` but without full per-message interest tracking. |
|
||||
| `outsie` struct | gateway.go:229 | PARTIAL | `src/NATS.Server/Gateways/GatewayInterestTracker.cs` | `GatewayInterestTracker.AccountState` covers mode and no-interest set. Missing: per-account `sl *Sublist` for queue-sub tracking in InterestOnly mode, `qsubs` counter. |
|
||||
| `insie` struct | gateway.go:256 | MISSING | — | Inbound per-account no-interest set with mode tracking. No distinct type in .NET; `GatewayInterestTracker` handles outbound-side equivalent but not the inbound RS-/RS+ tracking map. |
|
||||
@@ -131,9 +131,9 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `validateGatewayOptions` | gateway.go:306 | MISSING | — | Validates gateway config (name, port, remote URLs). No validation equivalent in .NET. |
|
||||
| `getGWHash` (standalone) | gateway.go:335 | MISSING | — | Computes 6-char hash for gateway name. Used for reply prefix construction. Not ported. |
|
||||
| `getOldHash` (standalone) | gateway.go:339 | MISSING | — | SHA-256-based 4-char hash for old `$GR.` prefix. Not ported. |
|
||||
| `validateGatewayOptions` | gateway.go:306 | PORTED | `src/NATS.Server/Gateways/GatewayManager.cs:113` (`ValidateGatewayOptions`) | Basic gateway config validation implemented for required name, valid port range, and non-empty remotes. |
|
||||
| `getGWHash` (standalone) | gateway.go:335 | PORTED | `src/NATS.Server/Gateways/ReplyMapper.cs:75` (`ComputeGatewayHash`) | Deterministic short gateway hash helper implemented (6-char hex). |
|
||||
| `getOldHash` (standalone) | gateway.go:339 | PORTED | `src/NATS.Server/Gateways/ReplyMapper.cs:85` (`ComputeOldGatewayHash`) | Deterministic legacy short hash helper implemented (4-char hex). |
|
||||
| `Server.newGateway` | gateway.go:350 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:90` | `GatewayManager` constructor covers basic setup. Missing: hash computation, reply prefix assembly, `oldReplyPfx`, `pasi` init, resolver config. |
|
||||
| `Server.startGateways` | gateway.go:487 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:161` (`StartAsync`) | `StartAsync` starts accept loop and connects to remotes. Missing: solicit delay, cluster-formation wait. |
|
||||
| `Server.startGatewayAcceptLoop` | gateway.go:511 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:326` (`AcceptLoopAsync`) | Accept loop exists. Missing: TLS config, `authRequired`, reject-unknown check, advertising, `GatewayIOM` flag, INFO protocol send. |
|
||||
@@ -141,7 +141,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `Server.solicitGateways` | gateway.go:668 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:173` (`StartAsync` remote loop) | Connects to configured remotes. Missing: implicit vs explicit distinction, goroutine-per-remote with proper lifecycle. |
|
||||
| `Server.reconnectGateway` | gateway.go:689 | PORTED | `src/NATS.Server/Gateways/GatewayManager.cs:149` (`ReconnectGatewayAsync`) | Exponential backoff reconnect delay with jitter. |
|
||||
| `Server.solicitGateway` | gateway.go:706 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:358` (`ConnectWithRetryAsync`) | Retry loop with multiple URL support. Missing: random URL selection, `shouldReportConnectErr` throttling, implicit gateway retry limits, DNS resolution via `resolver`, `ConnectBackoff` flag. |
|
||||
| `srvGateway.hasInbound` | gateway.go:790 | MISSING | — | Checks if an inbound connection for a named gateway exists. Not implemented. |
|
||||
| `srvGateway.hasInbound` | gateway.go:790 | PORTED | `src/NATS.Server/Gateways/GatewayManager.cs:345` (`HasInbound`) | Inbound-connection presence check is implemented by remote server id. |
|
||||
| `Server.createGateway` | gateway.go:805 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:344` (`HandleInboundAsync`) and `ConnectWithRetryAsync` | Creates client connection for inbound/outbound. Missing: full client lifecycle, TLS handshake, CONNECT/INFO protocol, `expectConnect` flag, ping timer setup, temp-client registration. |
|
||||
| `client.sendGatewayConnect` | gateway.go:958 | PARTIAL | `src/NATS.Server/Gateways/GatewayConnection.cs:113` (`PerformOutboundHandshakeAsync`) | Handshake sends server ID. Go sends full CONNECT JSON with auth, TLS flag, gateway name. .NET sends a simplified `GATEWAY {serverId}` line. |
|
||||
| `client.processGatewayConnect` | gateway.go:993 | MISSING | — | Parses CONNECT from inbound gateway; validates gateway field, rejects wrong port/unknown gateways. No protocol parsing in .NET. |
|
||||
@@ -155,32 +155,32 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `Server.processGatewayInfoFromRoute` | gateway.go:1394 | MISSING | — | Handles gateway gossip INFO received via a cluster route connection. |
|
||||
| `Server.sendGatewayConfigsToRoute` | gateway.go:1406 | MISSING | — | Sends known outbound gateway configs to a new route connection. |
|
||||
| `Server.processImplicitGateway` | gateway.go:1453 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:119` (`ProcessImplicitGateway`) | Records discovered gateway name. Missing: URL augmentation of existing config, creation of `gatewayCfg`, launching `solicitGateway` goroutine for the new implicit remote. |
|
||||
| `Server.NumOutboundGateways` | gateway.go:1501 | MISSING | — | Public test-facing count of outbound connections. No exact equivalent. |
|
||||
| `Server.numOutboundGateways` | gateway.go:1506 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:284` (`GetConnectedGatewayCount`) | Returns connected count from registrations. Does not distinguish inbound vs outbound. |
|
||||
| `Server.numInboundGateways` | gateway.go:1514 | MISSING | — | Count of inbound gateway connections. No equivalent. |
|
||||
| `Server.NumOutboundGateways` | gateway.go:1501 | PORTED | `src/NATS.Server/NatsServer.cs:155` (`NumOutboundGateways`) | Public server-facing outbound gateway count now exposed. |
|
||||
| `Server.numOutboundGateways` | gateway.go:1506 | PORTED | `src/NATS.Server/Gateways/GatewayManager.cs:331` (`NumOutboundGateways`) | Manager now computes outbound count from live connection direction (`IsOutbound`). |
|
||||
| `Server.numInboundGateways` | gateway.go:1514 | PORTED | `src/NATS.Server/Gateways/GatewayManager.cs:338` (`NumInboundGateways`), `src/NATS.Server/NatsServer.cs:156` | Inbound gateway count is now tracked and exposed. |
|
||||
| `Server.getRemoteGateway` | gateway.go:1522 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:264` (`GetRegistration`) | Returns registration by name. Missing: returns `gatewayCfg` in Go (with TLS, URLs, hash); .NET returns `GatewayRegistration` (only state/stats). |
|
||||
| `gatewayCfg.bumpConnAttempts` | gateway.go:1530 | MISSING | — | Test helper to increment connection attempts counter. |
|
||||
| `gatewayCfg.getConnAttempts` | gateway.go:1537 | MISSING | — | Test helper to read connection attempts. |
|
||||
| `gatewayCfg.resetConnAttempts` | gateway.go:1545 | MISSING | — | Test helper to reset connection attempts. |
|
||||
| `gatewayCfg.isImplicit` | gateway.go:1552 | MISSING | — | Returns whether a gateway config was discovered (implicit) vs configured (explicit). |
|
||||
| `gatewayCfg.getURLs` | gateway.go:1561 | MISSING | — | Returns randomly shuffled URL slice for connection attempts. |
|
||||
| `gatewayCfg.getURLsAsStrings` | gateway.go:1576 | MISSING | — | Returns URL host strings for gossip INFO. |
|
||||
| `gatewayCfg.updateURLs` | gateway.go:1588 | MISSING | — | Rebuilds URL map from config + INFO-discovered URLs. |
|
||||
| `gatewayCfg.saveTLSHostname` | gateway.go:1612 | MISSING | — | Saves TLS ServerName from a URL hostname. TLS not implemented. |
|
||||
| `gatewayCfg.addURLs` | gateway.go:1621 | MISSING | — | Adds newly discovered URLs into the URL map. |
|
||||
| `gatewayCfg.bumpConnAttempts` | gateway.go:1530 | PORTED | `src/NATS.Server/Configuration/GatewayOptions.cs:57` (`RemoteGatewayOptions.BumpConnAttempts`) | Added connection-attempt increment helper. |
|
||||
| `gatewayCfg.getConnAttempts` | gateway.go:1537 | PORTED | `src/NATS.Server/Configuration/GatewayOptions.cs:59` (`RemoteGatewayOptions.GetConnAttempts`) | Added connection-attempt read helper. |
|
||||
| `gatewayCfg.resetConnAttempts` | gateway.go:1545 | PORTED | `src/NATS.Server/Configuration/GatewayOptions.cs:61` (`RemoteGatewayOptions.ResetConnAttempts`) | Added connection-attempt reset helper. |
|
||||
| `gatewayCfg.isImplicit` | gateway.go:1552 | PORTED | `src/NATS.Server/Configuration/GatewayOptions.cs:63` (`RemoteGatewayOptions.IsImplicit`) | Added implicit-vs-explicit gateway config query. |
|
||||
| `gatewayCfg.getURLs` | gateway.go:1561 | PORTED | `src/NATS.Server/Configuration/GatewayOptions.cs:65` (`RemoteGatewayOptions.GetUrls`) | Added normalized + shuffled URL list helper for connection attempts. |
|
||||
| `gatewayCfg.getURLsAsStrings` | gateway.go:1576 | PORTED | `src/NATS.Server/Configuration/GatewayOptions.cs:84` (`RemoteGatewayOptions.GetUrlsAsStrings`) | Added URL string projection helper for gossip/config sync paths. |
|
||||
| `gatewayCfg.updateURLs` | gateway.go:1588 | PORTED | `src/NATS.Server/Configuration/GatewayOptions.cs:92` (`RemoteGatewayOptions.UpdateUrls`) | Added merged configured+discovered URL rebuild helper with normalization/deduplication. |
|
||||
| `gatewayCfg.saveTLSHostname` | gateway.go:1612 | PORTED | `src/NATS.Server/Configuration/GatewayOptions.cs:100` (`RemoteGatewayOptions.SaveTlsHostname`) | Added TLS hostname extraction/storage from URL host. |
|
||||
| `gatewayCfg.addURLs` | gateway.go:1621 | PORTED | `src/NATS.Server/Configuration/GatewayOptions.cs:106` (`RemoteGatewayOptions.AddUrls`) | Added incremental discovered-URL add helper with normalization/deduplication. |
|
||||
| `Server.addGatewayURL` | gateway.go:1648 | MISSING | — | Adds a URL to the server's gateway URL set and regenerates INFO JSON. |
|
||||
| `Server.removeGatewayURL` | gateway.go:1661 | MISSING | — | Removes a URL from the gateway URL set and regenerates INFO JSON. |
|
||||
| `Server.sendAsyncGatewayInfo` | gateway.go:1676 | MISSING | — | Sends updated INFO to all inbound gateway connections (e.g., after URL change). |
|
||||
| `Server.getGatewayURL` | gateway.go:1688 | MISSING | — | Returns this server's gateway listen URL string. |
|
||||
| `Server.getGatewayName` | gateway.go:1697 | MISSING | — | Returns this server's gateway cluster name. |
|
||||
| `Server.getGatewayURL` | gateway.go:1688 | PORTED | `src/NATS.Server/NatsServer.cs:259` | Added gateway listen URL accessor that returns configured listen endpoint when gateway manager is present. |
|
||||
| `Server.getGatewayName` | gateway.go:1697 | PORTED | `src/NATS.Server/NatsServer.cs:260` | Added gateway name accessor returning configured gateway cluster name. |
|
||||
| `Server.getAllGatewayConnections` | gateway.go:1703 | MISSING | — | Collects all inbound + outbound gateway clients into a map. |
|
||||
| `Server.registerInboundGatewayConnection` | gateway.go:1720 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:392` (`Register`) | `Register` adds connection to dictionary. Missing: separate inbound map keyed by CID. |
|
||||
| `Server.registerOutboundGatewayConnection` | gateway.go:1728 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:392` (`Register`) | `Register` handles registration. Missing: duplicate-prevention logic (return false if name already exists), RTT-ordered `outo` list. |
|
||||
| `Server.getOutboundGatewayConnection` | gateway.go:1743 | MISSING | — | Returns outbound connection by name. No named lookup of outbound connections. |
|
||||
| `Server.getOutboundGatewayConnections` | gateway.go:1752 | MISSING | — | Returns all outbound connections in RTT order. |
|
||||
| `Server.getInboundGatewayConnections` | gateway.go:1778 | MISSING | — | Returns all inbound connections. |
|
||||
| `Server.getOutboundGatewayConnection` | gateway.go:1743 | PORTED | `src/NATS.Server/Gateways/GatewayManager.cs:352` (`GetOutboundGatewayConnection`) | Outbound connection lookup by remote server id is implemented. |
|
||||
| `Server.getOutboundGatewayConnections` | gateway.go:1752 | PORTED | `src/NATS.Server/Gateways/GatewayManager.cs:359` (`GetOutboundGatewayConnections`) | Outbound connection snapshot enumeration is implemented. |
|
||||
| `Server.getInboundGatewayConnections` | gateway.go:1778 | PORTED | `src/NATS.Server/Gateways/GatewayManager.cs:366` (`GetInboundGatewayConnections`) | Inbound connection snapshot enumeration is implemented. |
|
||||
| `Server.removeRemoteGatewayConnection` | gateway.go:1788 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:416` (`WatchConnectionAsync`) | Removes connection and decrements stats. Missing: outbound-specific cleanup (delete from `outo`/`out`, remove qsub tracking from `totalQSubs`), inbound-specific cleanup (remove `_R_` subscriptions). |
|
||||
| `Server.GatewayAddr` | gateway.go:1862 | MISSING | — | Returns `*net.TCPAddr` for the gateway listener. No equivalent (only `ListenEndpoint` string). |
|
||||
| `Server.GatewayAddr` | gateway.go:1862 | PORTED | `src/NATS.Server/NatsServer.cs:258` | Added gateway address accessor. .NET returns `host:port` string endpoint rather than Go `*net.TCPAddr`. |
|
||||
| `client.processGatewayAccountUnsub` | gateway.go:1875 | PARTIAL | `src/NATS.Server/Gateways/GatewayInterestTracker.cs:86` (`TrackNoInterest`) | Tracks no-interest at account level. Missing: handling of queue subs (reset `ni` map but keep entry if `qsubs > 0`), Go's nil-vs-entry distinction in `outsim`. |
|
||||
| `client.processGatewayAccountSub` | gateway.go:1904 | PARTIAL | `src/NATS.Server/Gateways/GatewayInterestTracker.cs:61` (`TrackInterest`) | Clears no-interest in optimistic mode. Missing: queue-sub check (don't delete entry if `qsubs > 0`). |
|
||||
| `client.processGatewayRUnsub` | gateway.go:1934 | MISSING | — | Parses RS- protocol; for optimistic mode stores in ni map, for InterestOnly/queue removes from sublist. Full RS- processing not ported. |
|
||||
@@ -191,7 +191,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `Server.sendQueueSubOrUnsubToGateways` | gateway.go:2335 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:199` (`PropagateLocalUnsubscription`) | Propagates queue sub changes. Missing: wire RS+/RS- protocol, A- clearing logic. |
|
||||
| `Server.gatewayUpdateSubInterest` | gateway.go:2391 | MISSING | — | Ref-counted `pasi` map update + recent-sub tracking + triggers send to gateways. Core subscription-interest accounting not ported. |
|
||||
| `isGWRoutedReply` (standalone) | gateway.go:2484 | PORTED | `src/NATS.Server/Gateways/ReplyMapper.cs:17` (`HasGatewayReplyPrefix`) | Detects `_GR_.` prefix with length guard. |
|
||||
| `isGWRoutedSubjectAndIsOldPrefix` (standalone) | gateway.go:2490 | PARTIAL | `src/NATS.Server/Gateways/ReplyMapper.cs:17` | `HasGatewayReplyPrefix` checks new prefix only. Old `$GR.` prefix detection missing. |
|
||||
| `isGWRoutedSubjectAndIsOldPrefix` (standalone) | gateway.go:2490 | PORTED | `src/NATS.Server/Gateways/ReplyMapper.cs:31` (`IsGatewayRoutedSubject`) | Implemented explicit routed-subject detection with old-prefix flag output (`isOldPrefix`) for `_GR_.` and `$GR.`. |
|
||||
| `hasGWRoutedReplyPrefix` (standalone) | gateway.go:2502 | PORTED | `src/NATS.Server/Gateways/ReplyMapper.cs:17` (`HasGatewayReplyPrefix`) | Equivalent prefix check. |
|
||||
| `srvGateway.shouldMapReplyForGatewaySend` | gateway.go:2507 | MISSING | — | Checks `rsubs` sync.Map to decide if a reply subject needs gateway mapping. No `rsubs` equivalent. |
|
||||
| `client.sendMsgToGateways` | gateway.go:2540 | PARTIAL | `src/NATS.Server/Gateways/GatewayManager.cs:181` (`ForwardMessageAsync`) | Iterates connections and sends. Missing: direct-send path for `_GR_` subjects (hash routing), queue group filtering, reply subject mapping, header stripping for non-header peers, message tracing, per-account stats, RTT-ordered iteration. |
|
||||
@@ -211,7 +211,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `Server.trackGWReply` | gateway.go:3324 | PARTIAL | `src/NATS.Server/Gateways/ReplyMapper.cs:231` (`ReplyMapCache.Set`) | Caches reply mapping with TTL. Missing: per-client vs per-account duality, `gwrm.m` sync.Map for background cleanup, `check int32` atomic flag, `gwrm.ch` channel to trigger expiry timer. |
|
||||
| `Server.startGWReplyMapExpiration` | gateway.go:3371 | PARTIAL | `src/NATS.Server/Gateways/ReplyMapper.cs:267` (`ReplyMapCache.PurgeExpired`) | Purge is manual on-demand. Go runs a dedicated goroutine with timer reset on new entries via channel. No background expiry goroutine in .NET. |
|
||||
| `gwReplyMapping.get` | gateway.go:280 | PORTED | `src/NATS.Server/Gateways/ReplyMapper.cs:202` (`ReplyMapCache.TryGet`) | LRU get with TTL check. |
|
||||
| `RemoteGatewayOpts.clone` | gateway.go:290 | MISSING | — | Deep-copies a `RemoteGatewayOpts` including TLS config clone. No clone method on `RemoteGatewayOptions`. |
|
||||
| `RemoteGatewayOpts.clone` | gateway.go:290 | PORTED | `src/NATS.Server/Configuration/GatewayOptions.cs:36` (`RemoteGatewayOptions.Clone`) | Deep-copy helper implemented for remote gateway option name + URL list. |
|
||||
|
||||
#### Additional .NET-Only Types (No Go Equivalent)
|
||||
|
||||
@@ -247,5 +247,9 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Executed gateways batch 4 accessor parity slice: added server gateway accessors (`GatewayAddr`, `GetGatewayURL`, `GetGatewayName`) and targeted tests (`GatewayServerAccessorParityBatch4Tests`). Reclassified 3 rows to PORTED. | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Full gap inventory completed: analyzed all ~3,427 lines of gateway.go; classified 80+ Go symbols against 6 .NET source files. Final counts: 9 PORTED, 35 PARTIAL, 37 MISSING, 5 NOT_APPLICABLE. | claude-sonnet-4-6 |
|
||||
| 2026-02-25 | Ported gateway parity helper batch: reply-prefix/hash constants and old-prefix detection, gateway hash helpers (`getGWHash`/`getOldHash` analogs), gateway option validator, TLS warning constant, and `RemoteGatewayOptions.Clone`; added focused tests and updated status rows. | codex |
|
||||
| 2026-02-25 | Ported gateway connection-direction parity batch: added inbound/outbound classification (`IsOutbound`), count/lookups (`NumOutboundGateways`, `NumInboundGateways`, `HasInbound`, outbound/inbound connection snapshots), and server wrappers with focused tests. | codex |
|
||||
| 2026-02-25 | Ported gateway remote-config parity batch: added `RemoteGatewayOptions` attempt counters and URL lifecycle helpers (`Bump/Get/ResetConnAttempts`, `IsImplicit`, `GetUrls`, `GetUrlsAsStrings`, `UpdateUrls`, `SaveTlsHostname`, `AddUrls`) with focused tests (`GatewayRemoteConfigParityBatch3Tests`). | codex |
|
||||
|
||||
@@ -120,7 +120,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `SequenceSet.Union` (method) | `golang/nats-server/server/avl/seqset.go:191` | PORTED | `src/NATS.Server/Internal/Avl/SequenceSet.cs:203` | |
|
||||
| `Union` (function) | `golang/nats-server/server/avl/seqset.go:208` | PORTED | `src/NATS.Server/Internal/Avl/SequenceSet.cs:228` | `SequenceSet.CreateUnion` static method |
|
||||
| `SequenceSet.EncodeLen` | `golang/nats-server/server/avl/seqset.go:238` | PORTED | `src/NATS.Server/Internal/Avl/SequenceSet.cs:252` | `EncodeLength()` in .NET |
|
||||
| `SequenceSet.Encode` | `golang/nats-server/server/avl/seqset.go:242` | PARTIAL | `src/NATS.Server/Internal/Avl/SequenceSet.cs:255` | Go signature takes optional buf to reuse; .NET always allocates new. Behavior equivalent. |
|
||||
| `SequenceSet.Encode` | `golang/nats-server/server/avl/seqset.go:242` | PORTED | `src/NATS.Server/Internal/Avl/SequenceSet.cs:266` | Added destination-buffer overload (`Encode(byte[] destination)`) enabling caller buffer reuse parity |
|
||||
| `ErrBadEncoding` | `golang/nats-server/server/avl/seqset.go:276` | PORTED | `src/NATS.Server/Internal/Avl/SequenceSet.cs:288` | Thrown as `InvalidOperationException` |
|
||||
| `ErrBadVersion` | `golang/nats-server/server/avl/seqset.go:277` | PORTED | `src/NATS.Server/Internal/Avl/SequenceSet.cs:295` | Thrown as `InvalidOperationException` |
|
||||
| `ErrSetNotEmpty` | `golang/nats-server/server/avl/seqset.go:278` | PORTED | `src/NATS.Server/Internal/Avl/SequenceSet.cs:93` | Thrown as `InvalidOperationException` |
|
||||
@@ -166,9 +166,9 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `SubjectTree.match` (internal) | `golang/nats-server/server/stree/stree.go:318` | PORTED | `src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:383` | `MatchInternal` |
|
||||
| `SubjectTree.iter` (internal) | `golang/nats-server/server/stree/stree.go:418` | PORTED | `src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:512` | `IterInternal` |
|
||||
| `LazyIntersect[TL,TR]` | `golang/nats-server/server/stree/stree.go:463` | PORTED | `src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:584` | `SubjectTreeHelper.LazyIntersect` static |
|
||||
| `IntersectGSL[T,SL]` | `golang/nats-server/server/stree/stree.go:488` | MISSING | — | No .NET equivalent. Intersects stree with gsl.GenericSublist. Used in JetStream consumer NumPending. |
|
||||
| `_intersectGSL` (internal) | `golang/nats-server/server/stree/stree.go:496` | MISSING | — | Helper for IntersectGSL |
|
||||
| `hasInterestForTokens` (internal) | `golang/nats-server/server/stree/stree.go:521` | MISSING | — | Token-boundary interest check for GSL intersection |
|
||||
| `IntersectGSL[T,SL]` | `golang/nats-server/server/stree/stree.go:488` | PORTED | `src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:675` | Added GSL intersection traversal for subject tree entries |
|
||||
| `_intersectGSL` (internal) | `golang/nats-server/server/stree/stree.go:496` | PORTED | `src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:686` | Added recursive intersection helper |
|
||||
| `hasInterestForTokens` (internal) | `golang/nats-server/server/stree/stree.go:521` | PORTED | `src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:717` | Added token-boundary short-circuit using `HasInterestStartingIn` |
|
||||
| `bytesToString` (internal) | `golang/nats-server/server/stree/stree.go:534` | NOT_APPLICABLE | — | Go `unsafe` zero-copy string conversion. In .NET, `System.Text.Encoding.UTF8.GetString` or `MemoryMarshal.Cast` used instead |
|
||||
|
||||
---
|
||||
@@ -276,10 +276,10 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `SubjectTree.Dump` | `golang/nats-server/server/stree/dump.go:23` | MISSING | — | Debug utility for printing tree structure to an `io.Writer`. No .NET equivalent. Low priority — debug/diagnostic only. |
|
||||
| `SubjectTree.dump` (internal) | `golang/nats-server/server/stree/dump.go:29` | MISSING | — | Internal helper for Dump |
|
||||
| `dumpPre` | `golang/nats-server/server/stree/dump.go:59` | MISSING | — | Indentation helper for Dump |
|
||||
| `leaf.kind`, `node4.kind`, etc. | `golang/nats-server/server/stree/dump.go:51` | PARTIAL | `src/NATS.Server/Internal/SubjectTree/Nodes.cs` | `INode.Kind` property exists on each node type, but `Dump` method is not implemented |
|
||||
| `SubjectTree.Dump` | `golang/nats-server/server/stree/dump.go:23` | PORTED | `src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:172` | Added debug dump writer with root traversal and trailing newline |
|
||||
| `SubjectTree.dump` (internal) | `golang/nats-server/server/stree/dump.go:29` | PORTED | `src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:180` | Added recursive node/leaf dump helper |
|
||||
| `dumpPre` | `golang/nats-server/server/stree/dump.go:59` | PORTED | `src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:205` | Added indentation helper matching Go depth formatting |
|
||||
| `leaf.kind`, `node4.kind`, etc. | `golang/nats-server/server/stree/dump.go:51` | PORTED | `src/NATS.Server/Internal/SubjectTree/Nodes.cs:21` | `INode.Kind` values are now actively consumed by `SubjectTree.Dump` output |
|
||||
|
||||
---
|
||||
|
||||
@@ -291,7 +291,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `ErrInvalidVersion` | `golang/nats-server/server/thw/thw.go:28` | PORTED | `src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:289` | Thrown as `InvalidOperationException` |
|
||||
| `slot` (struct) | `golang/nats-server/server/thw/thw.go:39` | PORTED | `src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:406` | `Slot` internal class |
|
||||
| `HashWheel` (struct) | `golang/nats-server/server/thw/thw.go:45` | PORTED | `src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:17` | `HashWheel` class |
|
||||
| `HashWheelEntry` (struct) | `golang/nats-server/server/thw/thw.go:52` | MISSING | — | Go uses this struct for entry representation in some contexts; .NET uses `(ulong, long)` tuples inline instead |
|
||||
| `HashWheelEntry` (struct) | `golang/nats-server/server/thw/thw.go:52` | PORTED | `src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:407` | Added `HashWheelEntry` record struct (`Sequence`, `Expires`) |
|
||||
| `NewHashWheel` | `golang/nats-server/server/thw/thw.go:58` | PORTED | `src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:34` | Constructor in .NET |
|
||||
| `HashWheel.getPosition` (internal) | `golang/nats-server/server/thw/thw.go:66` | PORTED | `src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:50` | `GetPosition` private static |
|
||||
| `newSlot` (internal) | `golang/nats-server/server/thw/thw.go:71` | PORTED | `src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:406` | Inline slot initialization in .NET |
|
||||
@@ -315,7 +315,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `ErrNotFound` | `golang/nats-server/server/gsl/gsl.go:42` | PORTED | `src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:12` | `GslErrors.NotFound` |
|
||||
| `ErrNilChan` | `golang/nats-server/server/gsl/gsl.go:43` | NOT_APPLICABLE | — | Go channel-specific error; channels don't apply to .NET pattern |
|
||||
| `ErrAlreadyRegistered` | `golang/nats-server/server/gsl/gsl.go:44` | NOT_APPLICABLE | — | Used by notification channels in Go; no notification channel pattern in .NET port |
|
||||
| `SimpleSublist` (type alias) | `golang/nats-server/server/gsl/gsl.go:49` | PARTIAL | `src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:650` | `SimpleSubjectList` uses `int` instead of `struct{}`. Functionally equivalent but not a true zero-allocation alias |
|
||||
| `SimpleSublist` (type alias) | `golang/nats-server/server/gsl/gsl.go:49` | PORTED | `src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:656` | `SimpleSubjectList` now aliases `GenericSubjectList<SimpleSublistValue>` where marker value mirrors Go's empty struct payload |
|
||||
| `NewSimpleSublist` | `golang/nats-server/server/gsl/gsl.go:52` | PORTED | `src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:650` | `new SimpleSubjectList()` |
|
||||
| `GenericSublist[T]` (struct) | `golang/nats-server/server/gsl/gsl.go:57` | PORTED | `src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:76` | `GenericSubjectList<T>` |
|
||||
| `node[T]` (struct) | `golang/nats-server/server/gsl/gsl.go:64` | PORTED | `src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:52` | `Node<T>` |
|
||||
@@ -359,7 +359,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `ProcUsage` (freebsd/netbsd/openbsd/dragonfly/solaris/zos) | `golang/nats-server/server/pse/pse_*.go` | NOT_APPLICABLE | — | Platform-specific Go build-tagged files. .NET runtime abstracts these OS differences. |
|
||||
| `ProcUsage` (wasm/rumprun) | `golang/nats-server/server/pse/pse_wasm.go` | NOT_APPLICABLE | — | Stub/no-op implementations for unsupported platforms; not needed in .NET |
|
||||
| `updateUsage` (darwin, internal) | `golang/nats-server/server/pse/pse_darwin.go:56` | PORTED | `src/NATS.Server/Monitoring/VarzHandler.cs:39` | CPU sampling logic in VarzHandler |
|
||||
| `periodic` (darwin, internal) | `golang/nats-server/server/pse/pse_darwin.go:76` | PARTIAL | `src/NATS.Server/Monitoring/VarzHandler.cs:39` | Go runs periodic background timer; .NET samples on each `/varz` request with 1s cache. Semantics slightly different. |
|
||||
| `periodic` (darwin, internal) | `golang/nats-server/server/pse/pse_darwin.go:76` | PORTED | `src/NATS.Server/Monitoring/VarzHandler.cs:30` | Added 1s background timer sampler (`SampleCpuUsage`) with synchronized cached CPU reads in `/varz`, matching periodic semantics instead of request-only sampling |
|
||||
|
||||
---
|
||||
|
||||
@@ -367,9 +367,9 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `Memory` (darwin) | `golang/nats-server/server/sysmem/mem_darwin.go:18` | MISSING | — | Queries total physical RAM via `hw.memsize` sysctl. No .NET equivalent in codebase. Used by JetStream for sizing decisions. |
|
||||
| `Memory` (linux) | `golang/nats-server/server/sysmem/mem_linux.go:20` | MISSING | — | Queries via `syscall.Sysinfo`. No .NET equivalent found. |
|
||||
| `Memory` (windows) | `golang/nats-server/server/sysmem/mem_windows.go` | MISSING | — | No .NET equivalent found. Can be implemented via `GC.GetGCMemoryInfo().TotalAvailableMemoryBytes`. |
|
||||
| `Memory` (darwin) | `golang/nats-server/server/sysmem/mem_darwin.go:18` | PORTED | `src/NATS.Server/Internal/SysMem/SystemMemory.cs:12` | Added cross-platform `SystemMemory.Memory()` backed by runtime memory info |
|
||||
| `Memory` (linux) | `golang/nats-server/server/sysmem/mem_linux.go:20` | PORTED | `src/NATS.Server/Internal/SysMem/SystemMemory.cs:12` | Added cross-platform `SystemMemory.Memory()` backed by runtime memory info |
|
||||
| `Memory` (windows) | `golang/nats-server/server/sysmem/mem_windows.go` | PORTED | `src/NATS.Server/Internal/SysMem/SystemMemory.cs:12` | Added cross-platform `SystemMemory.Memory()` backed by runtime memory info |
|
||||
| `Memory` (bsd/solaris/wasm/zos) | `golang/nats-server/server/sysmem/mem_bsd.go` etc. | NOT_APPLICABLE | — | Platform-specific stubs; .NET runtime abstracts these. `GCMemoryInfo` is the cross-platform equivalent. |
|
||||
| `sysctlInt64` | `golang/nats-server/server/sysmem/sysctl.go:23` | NOT_APPLICABLE | — | Darwin/BSD internal helper using unsafe sysctl; .NET abstracts this entirely |
|
||||
|
||||
@@ -400,3 +400,4 @@ After porting work is completed:
|
||||
|------|--------|----|
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Full gap inventory populated: 157 PORTED, 4 PARTIAL, 10 MISSING, 8 NOT_APPLICABLE, 0 DEFERRED | auto |
|
||||
| 2026-02-25 | Completed periodic PSE parity by moving CPU sampling to a 1s background timer in `VarzHandler` and adding targeted parity test coverage | codex |
|
||||
|
||||
@@ -140,12 +140,12 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| JetStreamConfig (struct) | golang/nats-server/server/jetstream.go:42 | PARTIAL | src/NATS.Server/Configuration/JetStreamOptions.cs:5 | .NET has MaxMemoryStore, MaxFileStore, MaxStreams, MaxConsumers, Domain. Missing: SyncInterval, SyncAlways, CompressOK, UniqueTag, Strict fields |
|
||||
| JetStreamStats (struct) | golang/nats-server/server/jetstream.go:55 | MISSING | — | Server-level usage stats (Memory, Store, ReservedMemory, ReservedStore, Accounts, HAAssets, API) not modeled |
|
||||
| JetStreamAccountLimits (struct) | golang/nats-server/server/jetstream.go:65 | PARTIAL | src/NATS.Server/Configuration/JetStreamOptions.cs:5 | MaxStreams/MaxConsumers present. Missing: MaxAckPending, MemoryMaxStreamBytes, StoreMaxStreamBytes, MaxBytesRequired, tiered limits |
|
||||
| JetStreamTier (struct) | golang/nats-server/server/jetstream.go:76 | MISSING | — | Tiered accounting not implemented |
|
||||
| JetStreamConfig (struct) | golang/nats-server/server/jetstream.go:42 | PORTED | src/NATS.Server/Configuration/JetStreamOptions.cs | Added missing config fields: `SyncInterval`, `SyncAlways`, `CompressOk`, `UniqueTag`, `Strict` (plus parser wiring) |
|
||||
| JetStreamStats (struct) | golang/nats-server/server/jetstream.go:55 | PORTED | src/NATS.Server/JetStream/JetStreamParityModels.cs (`JetStreamStats`) | Added server-usage model with `Memory`, `Store`, `ReservedMemory`, `ReservedStore`, `Accounts`, `HaAssets`, and `Api` |
|
||||
| JetStreamAccountLimits (struct) | golang/nats-server/server/jetstream.go:65 | PORTED | src/NATS.Server/JetStream/JetStreamParityModels.cs (`JetStreamAccountLimits`), src/NATS.Server/Configuration/JetStreamOptions.cs | Added missing limits fields: `MaxAckPending`, `MemoryMaxStreamBytes`, `StoreMaxStreamBytes`, `MaxBytesRequired`, and tier map support |
|
||||
| JetStreamTier (struct) | golang/nats-server/server/jetstream.go:76 | PORTED | src/NATS.Server/JetStream/JetStreamParityModels.cs (`JetStreamTier`) | Added per-tier model (`Name`, `Memory`, `Store`, `Streams`, `Consumers`) |
|
||||
| JetStreamAccountStats (struct) | golang/nats-server/server/jetstream.go:87 | PARTIAL | src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:105 | JetStreamAccountInfo has Streams/Consumers counts only. Missing: memory/store usage, tiers, domain, API stats |
|
||||
| JetStreamAPIStats (struct) | golang/nats-server/server/jetstream.go:95 | MISSING | — | API level/total/errors/inflight stats not tracked |
|
||||
| JetStreamAPIStats (struct) | golang/nats-server/server/jetstream.go:95 | PORTED | src/NATS.Server/JetStream/JetStreamParityModels.cs (`JetStreamApiStats`) | Added API stats model with `Level`, `Total`, `Errors`, `Inflight` |
|
||||
| jetStream (internal struct) | golang/nats-server/server/jetstream.go:103 | PARTIAL | src/NATS.Server/JetStream/JetStreamService.cs:11 | JetStreamService covers lifecycle. Missing: apiInflight/apiTotal/apiErrors atomics, memUsed/storeUsed tracking, accounts map, apiSubs, cluster, oos/shuttingDown state |
|
||||
| jsAccount (internal struct) | golang/nats-server/server/jetstream.go:151 | MISSING | — | Per-account JetStream state (streams map, usage tracking, cluster usage updates) not modeled |
|
||||
| jsaUsage (internal struct) | golang/nats-server/server/jetstream.go:181 | MISSING | — | Per-account mem/store usage tracking |
|
||||
@@ -164,12 +164,12 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| enableAllJetStreamServiceImportsAndMappings (Account method) | golang/nats-server/server/jetstream.go:714 | MISSING | — | Per-account service imports and domain mappings |
|
||||
| configJetStream (Server method) | golang/nats-server/server/jetstream.go:771 | MISSING | — | Per-account JS config (enable/update/disable) |
|
||||
| configAllJetStreamAccounts (Server method) | golang/nats-server/server/jetstream.go:809 | MISSING | — | Walk all accounts and restore JetStream state |
|
||||
| JetStreamEnabled (Server method) | golang/nats-server/server/jetstream.go:904 | PARTIAL | src/NATS.Server/JetStream/JetStreamService.cs:48 | IsRunning property equivalent |
|
||||
| JetStreamEnabled (Server method) | golang/nats-server/server/jetstream.go:904 | PORTED | src/NATS.Server/NatsServer.cs:159 (`JetStreamEnabled`) | Server-level JetStream enabled check now exposed and backed by service running state |
|
||||
| JetStreamEnabledForDomain (Server method) | golang/nats-server/server/jetstream.go:909 | MISSING | — | Domain-wide JS availability check |
|
||||
| signalPullConsumers (Server method) | golang/nats-server/server/jetstream.go:930 | MISSING | — | Shutdown signal to R1 pull consumers |
|
||||
| shutdownJetStream (Server method) | golang/nats-server/server/jetstream.go:977 | PARTIAL | src/NATS.Server/JetStream/JetStreamService.cs:141 | Basic cleanup in DisposeAsync. Missing: account removal, cluster qch signaling |
|
||||
| JetStreamConfig (Server method) | golang/nats-server/server/jetstream.go:1055 | MISSING | — | Returns copy of current config |
|
||||
| StoreDir (Server method) | golang/nats-server/server/jetstream.go:1065 | MISSING | — | Returns current StoreDir |
|
||||
| JetStreamConfig (Server method) | golang/nats-server/server/jetstream.go:1055 | PORTED | src/NATS.Server/NatsServer.cs:161 (`JetStreamConfig`) | Returns a copy of configured JetStream options (store dir, limits, domain) |
|
||||
| StoreDir (Server method) | golang/nats-server/server/jetstream.go:1065 | PORTED | src/NATS.Server/NatsServer.cs:177 (`StoreDir`) | Server now exposes current configured JetStream store directory |
|
||||
| JetStreamNumAccounts (Server method) | golang/nats-server/server/jetstream.go:1074 | MISSING | — | Enabled account count |
|
||||
| JetStreamReservedResources (Server method) | golang/nats-server/server/jetstream.go:1085 | MISSING | — | Reserved mem/store bytes |
|
||||
| Account.EnableJetStream | golang/nats-server/server/jetstream.go:1107 | MISSING | — | Per-account JS enablement with limits, store dir, cluster usage |
|
||||
@@ -194,14 +194,14 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| jsAccount.reservedStorage | golang/nats-server/server/jetstream.go:1801 | MISSING | — | Reserved bytes by tier |
|
||||
| jsAccount.delete | golang/nats-server/server/jetstream.go:2481 | MISSING | — | Delete all JS resources for account |
|
||||
| dynJetStreamConfig (Server method) | golang/nats-server/server/jetstream.go:2659 | MISSING | — | Dynamic config: 75% sysmem, disk available |
|
||||
| isValidName | golang/nats-server/server/jetstream.go:2735 | MISSING | — | Name validation (no spaces, wildcards) |
|
||||
| isValidName | golang/nats-server/server/jetstream.go:2735 | PORTED | src/NATS.Server/JetStream/Validation/JetStreamConfigValidator.cs:10 | `IsValidName` enforces non-empty names, UTF-8 max 255 bytes, and rejects whitespace / `*` / `>`; applied in stream + consumer create paths |
|
||||
| friendlyBytes | golang/nats-server/server/jetstream.go:2723 | NOT_APPLICABLE | — | Logging helper; .NET has built-in formatting |
|
||||
| tierName | golang/nats-server/server/jetstream.go:2316 | MISSING | — | Compute tier name from replica count |
|
||||
| validateJetStreamOptions | golang/nats-server/server/jetstream.go:2767 | MISSING | — | Validates JS options (domain, cluster, etc.) |
|
||||
| fixCfgMirrorWithDedupWindow | golang/nats-server/server/jetstream.go:2848 | NOT_APPLICABLE | — | Bug fix for legacy config; not needed in new port |
|
||||
| JetStreamStoreDir (const) | golang/nats-server/server/jetstream.go:2649 | MISSING | — | "jetstream" directory name constant |
|
||||
| JetStreamMaxStoreDefault (const) | golang/nats-server/server/jetstream.go:2651 | MISSING | — | Default 1TB disk limit |
|
||||
| JetStreamMaxMemDefault (const) | golang/nats-server/server/jetstream.go:2653 | MISSING | — | Default 256MB mem limit |
|
||||
| JetStreamStoreDir (const) | golang/nats-server/server/jetstream.go:2649 | PORTED | src/NATS.Server/Configuration/JetStreamOptions.cs:8 | Added Go-parity constant `"jetstream"` |
|
||||
| JetStreamMaxStoreDefault (const) | golang/nats-server/server/jetstream.go:2651 | PORTED | src/NATS.Server/Configuration/JetStreamOptions.cs:9 | Added Go-parity default max store constant (`1 TiB`) |
|
||||
| JetStreamMaxMemDefault (const) | golang/nats-server/server/jetstream.go:2653 | PORTED | src/NATS.Server/Configuration/JetStreamOptions.cs:10 | Added Go-parity default max memory constant (`256 MiB`) |
|
||||
| Stream recovery logic (doStream/doConsumers) | golang/nats-server/server/jetstream.go:1223-1636 | MISSING | — | Full stream/consumer recovery from disk: metafile reading, checksum, encryption, versioning, subject repair |
|
||||
| keyGen (type) | golang/nats-server/server/jetstream.go:237 | MISSING | — | Key generation function signature for encryption |
|
||||
| resourcesExceededError (Server method) | golang/nats-server/server/jetstream.go:2743 | MISSING | — | Throttled error logging + meta leader stepdown |
|
||||
@@ -213,10 +213,10 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| JSApi* subject constants (50+) | golang/nats-server/server/jetstream_api.go:36-312 | PORTED | src/NATS.Server/JetStream/Api/JetStreamApiSubjects.cs:1 | All major API subjects defined. Minor: some template variants (T-suffixed) not needed in .NET |
|
||||
| JSAdvisory* prefix constants (25+) | golang/nats-server/server/jetstream_api.go:229-311 | PARTIAL | src/NATS.Server/JetStream/Api/AdvisoryPublisher.cs:1 | Stream create/delete/update, consumer create/delete covered. Missing: snapshot, restore, leader elected, quorum lost, batch abandoned, out-of-storage, server removed, API limit, pause, pinned, unpinned advisory prefixes |
|
||||
| JSMaxDescriptionLen (const) | golang/nats-server/server/jetstream_api.go:352 | MISSING | — | 4096 byte limit for descriptions |
|
||||
| JSMaxMetadataLen (const) | golang/nats-server/server/jetstream_api.go:356 | MISSING | — | 128KB metadata map size limit |
|
||||
| JSMaxNameLen (const) | golang/nats-server/server/jetstream_api.go:360 | MISSING | — | 255 char name length limit |
|
||||
| JSDefaultRequestQueueLimit (const) | golang/nats-server/server/jetstream_api.go:364 | MISSING | — | 10,000 request queue limit |
|
||||
| JSMaxDescriptionLen (const) | golang/nats-server/server/jetstream_api.go:352 | PORTED | src/NATS.Server/JetStream/Api/JetStreamApiLimits.cs:10 | Added Go-parity constant and enforced in stream create/update validation (`StreamManager`) |
|
||||
| JSMaxMetadataLen (const) | golang/nats-server/server/jetstream_api.go:356 | PORTED | src/NATS.Server/JetStream/Api/JetStreamApiLimits.cs:11 | Added Go-parity constant; metadata byte-size helper validates stream/consumer metadata against this limit |
|
||||
| JSMaxNameLen (const) | golang/nats-server/server/jetstream_api.go:360 | PORTED | src/NATS.Server/JetStream/Api/JetStreamApiLimits.cs:12 | Added Go-parity constant; name validation uses UTF-8 byte length limit through `JetStreamConfigValidator.IsValidName` |
|
||||
| JSDefaultRequestQueueLimit (const) | golang/nats-server/server/jetstream_api.go:364 | PORTED | src/NATS.Server/JetStream/Api/JetStreamApiLimits.cs:13 | Added Go-parity default request queue limit constant for JetStream API request orchestration |
|
||||
| ApiResponse (struct) | golang/nats-server/server/jetstream_api.go:369 | PARTIAL | src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:5 | Type field missing; error structure simplified |
|
||||
| ApiPaged / ApiPagedRequest (structs) | golang/nats-server/server/jetstream_api.go:395-404 | MISSING | — | Paged API request/response not implemented |
|
||||
| JSApiAccountInfoResponse | golang/nats-server/server/jetstream_api.go:407 | PARTIAL | src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:105 | Basic streams/consumers count. Missing: full JetStreamAccountStats embedding |
|
||||
@@ -1933,3 +1933,5 @@ After porting work is completed:
|
||||
| 2026-02-25 | JS-5c: jetstream_cluster.go lines 8001-end. 77 symbols. PORTED:8 PARTIAL:13 MISSING:56 | opus |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | JS-1 Core sub-pass: analyzed jetstream.go, jetstream_api.go, jetstream_events.go, jetstream_errors.go, jetstream_versioning.go, jetstream_batching.go. 150+ symbols inventoried. | opus |
|
||||
| 2026-02-25 | JS core config parity batch: added JetStream default constants (`JetStreamStoreDir`, max store/mem defaults) and server accessors (`JetStreamEnabled`, `JetStreamConfig`, `StoreDir`) with focused tests | codex |
|
||||
| 2026-02-26 | JS config/model parity batch: extended `JetStreamOptions` (sync/compress/strict/unique-tag and account-limit fields), added parser support for extended jetstream config keys, and added core parity models (`JetStreamStats`, `JetStreamApiStats`, `JetStreamAccountLimits`, `JetStreamTier`) with focused tests | codex |
|
||||
|
||||
@@ -92,45 +92,45 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `leafnodeTLSInsecureWarning` (const) | `golang/nats-server/server/leafnode.go:47` | PORTED | `src/NATS.Server/LeafNodes/LeafNodeManager.cs` | Warning logged in `DisableLeafConnect`; same semantic intent, no separate constant |
|
||||
| `leafNodeReconnectDelayAfterLoopDetected` (const) | `golang/nats-server/server/leafnode.go:50` | MISSING | — | 30s reconnect delay after loop detection. .NET loop detector (`LeafLoopDetector`) detects but does not enforce the delay on reconnect |
|
||||
| `leafNodeReconnectAfterPermViolation` (const) | `golang/nats-server/server/leafnode.go:54` | MISSING | — | 30s reconnect delay after permission violation. No .NET equivalent enforced |
|
||||
| `leafNodeReconnectDelayAfterClusterNameSame` (const) | `golang/nats-server/server/leafnode.go:57` | MISSING | — | 30s delay when same cluster name detected. No .NET equivalent |
|
||||
| `leafNodeReconnectDelayAfterLoopDetected` (const) | `golang/nats-server/server/leafnode.go:50` | PARTIAL | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:19`, `src/NATS.Server/LeafNodes/LeafConnection.cs` | Delay constant is now consumed by `LeafConnection.LeafProcessErr` for loop ERR processing. Remaining: reconnect loop still does not schedule by this delay automatically |
|
||||
| `leafNodeReconnectAfterPermViolation` (const) | `golang/nats-server/server/leafnode.go:54` | PARTIAL | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:20`, `src/NATS.Server/LeafNodes/LeafConnection.cs` | Delay constant is now consumed by `LeafPermViolation` / `LeafSubPermViolation`. Remaining: no enforced wait-before-redial in reconnect worker |
|
||||
| `leafNodeReconnectDelayAfterClusterNameSame` (const) | `golang/nats-server/server/leafnode.go:57` | PARTIAL | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:21`, `src/NATS.Server/LeafNodes/LeafConnection.cs` | Delay constant is now consumed by `LeafProcessErr` cluster-name path. Remaining: reconnect loop integration not complete |
|
||||
| `leafNodeLoopDetectionSubjectPrefix` (const `"$LDS."`) | `golang/nats-server/server/leafnode.go:60` | PORTED | `src/NATS.Server/LeafNodes/LeafLoopDetector.cs:5` | `LeafLoopPrefix = "$LDS."` |
|
||||
| `leafNodeWSPath` (const `"/leafnode"`) | `golang/nats-server/server/leafnode.go:64` | PORTED | `src/NATS.Server/LeafNodes/WebSocketStreamAdapter.cs` | Path constant is implicit in the WS adapter; not a named constant in .NET |
|
||||
| `leafNodeWaitBeforeClose` (const 5s) | `golang/nats-server/server/leafnode.go:68` | MISSING | — | Minimum version wait-before-close timer. Not ported |
|
||||
| `leaf` (unexported struct) | `golang/nats-server/server/leafnode.go:71` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs` | `LeafConnection` covers `remote`, `isSpoke`, `remoteCluster`, `remoteServer`, `remoteDomain`. Missing: `isolated`, `smap`, `tsub/tsubt` (transient sub map), `compression`, `gwSub` |
|
||||
| `leafNodeCfg` (unexported struct) | `golang/nats-server/server/leafnode.go:107` | PARTIAL | `src/NATS.Server/Configuration/LeafNodeOptions.cs` | `RemoteLeafOptions` covers URLs, credentials, local account. Missing: `curURL`, `tlsName`, `username/password` (runtime fields), `perms`, `connDelay`, `jsMigrateTimer` |
|
||||
| `leafConnectInfo` (unexported struct) | `golang/nats-server/server/leafnode.go:2001` | MISSING | — | JSON CONNECT payload for leaf solicited connections (JWT, Nkey, Sig, Hub, Cluster, Headers, JetStream, Compression, RemoteAccount, Proto). Not represented in .NET |
|
||||
| `leafNodeWaitBeforeClose` (const 5s) | `golang/nats-server/server/leafnode.go:68` | PARTIAL | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:22` | Constant is defined (`LeafNodeWaitBeforeClose = 5s`), but close-path wait timer behavior is not yet wired |
|
||||
| `leaf` (unexported struct) | `golang/nats-server/server/leafnode.go:71` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs` | `LeafConnection` now tracks role flags (`IsSolicited`, `IsSpoke`, `Isolated`) and helper predicates. Missing: `smap`, `tsub/tsubt`, `compression`, `gwSub`, remote cluster/server metadata parity |
|
||||
| `leafNodeCfg` (unexported struct) | `golang/nats-server/server/leafnode.go:107` | PARTIAL | `src/NATS.Server/Configuration/LeafNodeOptions.cs:7` (`RemoteLeafOptions`) | Added runtime parity fields/helpers (`CurrentUrl`, `TlsName`, URL user-info, connect-delay storage, round-robin URL picker). Remaining gaps: perms and JS migrate timer wiring |
|
||||
| `leafConnectInfo` (unexported struct) | `golang/nats-server/server/leafnode.go:2001` | PORTED | `src/NATS.Server/LeafNodes/LeafConnectInfo.cs` | CONNECT payload DTO now represented with Go-parity JSON fields (`jwt`, `nkey`, `sig`, `hub`, `cluster`, `headers`, `jetstream`, `compression`, `remote_account`, `proto`) |
|
||||
|
||||
#### Methods on `client` (receiver functions)
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `(c *client) isSolicitedLeafNode()` | `golang/nats-server/server/leafnode.go:121` | MISSING | — | No `client` type in .NET; `LeafConnection` does not track solicited vs. accepted role |
|
||||
| `(c *client) isSpokeLeafNode()` | `golang/nats-server/server/leafnode.go:127` | MISSING | — | Hub/spoke role tracking missing in .NET |
|
||||
| `(c *client) isHubLeafNode()` | `golang/nats-server/server/leafnode.go:131` | MISSING | — | Hub role helper missing in .NET |
|
||||
| `(c *client) isIsolatedLeafNode()` | `golang/nats-server/server/leafnode.go:135` | MISSING | — | Isolation flag not tracked in .NET |
|
||||
| `(c *client) sendLeafConnect(clusterName, headers)` | `golang/nats-server/server/leafnode.go:969` | MISSING | — | Sends CONNECT JSON payload (JWT/NKey/creds auth) on solicited connections. .NET handshake only sends `LEAF <id>` line |
|
||||
| `(c *client) isSolicitedLeafNode()` | `golang/nats-server/server/leafnode.go:121` | PORTED | `src/NATS.Server/LeafNodes/LeafConnection.cs:29,169` | Solicited role is tracked (`IsSolicited`) and exposed via `IsSolicitedLeafNode()` |
|
||||
| `(c *client) isSpokeLeafNode()` | `golang/nats-server/server/leafnode.go:127` | PORTED | `src/NATS.Server/LeafNodes/LeafConnection.cs:35,170` | Spoke role is tracked (`IsSpoke`) and exposed via `IsSpokeLeafNode()` |
|
||||
| `(c *client) isHubLeafNode()` | `golang/nats-server/server/leafnode.go:131` | PORTED | `src/NATS.Server/LeafNodes/LeafConnection.cs:171` | Hub-role helper implemented as the complement of spoke role (`!IsSpoke`) |
|
||||
| `(c *client) isIsolatedLeafNode()` | `golang/nats-server/server/leafnode.go:135` | PORTED | `src/NATS.Server/LeafNodes/LeafConnection.cs:41,172` | Isolation flag is tracked (`Isolated`) and exposed via `IsIsolatedLeafNode()` |
|
||||
| `(c *client) sendLeafConnect(clusterName, headers)` | `golang/nats-server/server/leafnode.go:969` | PORTED | `src/NATS.Server/LeafNodes/LeafConnection.cs` (`SendLeafConnectAsync`) | Added CONNECT protocol writer that serializes `LeafConnectInfo` JSON payload and writes `CONNECT <json>` |
|
||||
| `(c *client) leafClientHandshakeIfNeeded(remote, opts)` | `golang/nats-server/server/leafnode.go:1402` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs:80` | .NET `PerformOutboundHandshakeAsync` performs the handshake but without TLS negotiation or TLS-first logic |
|
||||
| `(c *client) processLeafnodeInfo(info)` | `golang/nats-server/server/leafnode.go:1426` | MISSING | — | Complex INFO protocol processing (TLS negotiation, compression selection, URL updates, permission updates). Not ported |
|
||||
| `(c *client) updateLeafNodeURLs(info)` | `golang/nats-server/server/leafnode.go:1711` | MISSING | — | Dynamically updates remote URL list from async INFO. Not ported |
|
||||
| `(c *client) doUpdateLNURLs(cfg, scheme, URLs)` | `golang/nats-server/server/leafnode.go:1732` | MISSING | — | Helper for `updateLeafNodeURLs`. Not ported |
|
||||
| `(c *client) remoteCluster()` | `golang/nats-server/server/leafnode.go:2235` | MISSING | — | Returns remote cluster name. Not tracked in .NET |
|
||||
| `(c *client) remoteCluster()` | `golang/nats-server/server/leafnode.go:2235` | PORTED | `src/NATS.Server/LeafNodes/LeafConnection.cs` (`RemoteCluster`) | Handshake parser now captures `cluster=...` attribute and exposes it via `RemoteCluster()` |
|
||||
| `(c *client) updateSmap(sub, delta, isLDS)` | `golang/nats-server/server/leafnode.go:2522` | MISSING | — | Core subject-map delta updates. .NET has `PropagateLocalSubscription` but no per-connection smap with refcounting |
|
||||
| `(c *client) forceAddToSmap(subj)` | `golang/nats-server/server/leafnode.go:2567` | MISSING | — | Force-inserts a subject into the smap. Not ported |
|
||||
| `(c *client) forceRemoveFromSmap(subj)` | `golang/nats-server/server/leafnode.go:2584` | MISSING | — | Force-removes a subject from the smap. Not ported |
|
||||
| `(c *client) sendLeafNodeSubUpdate(key, n)` | `golang/nats-server/server/leafnode.go:2607` | PARTIAL | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:265` | `PropagateLocalSubscription` / `PropagateLocalUnsubscription` send LS+/LS-. Missing: spoke permission check before sending, queue weight encoding |
|
||||
| `(c *client) writeLeafSub(w, key, n)` | `golang/nats-server/server/leafnode.go:2687` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs:108` | `SendLsPlusAsync`/`SendLsMinusAsync` write LS+/LS-. Missing: queue weight (`n`) in LS+ for queue subs |
|
||||
| `(c *client) processLeafSub(argo)` | `golang/nats-server/server/leafnode.go:2720` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs:190` | Read loop parses LS+ lines. Missing: loop detection check, permission check, subscription insertion into SubList, route/gateway propagation, queue weight delta handling |
|
||||
| `(c *client) sendLeafNodeSubUpdate(key, n)` | `golang/nats-server/server/leafnode.go:2607` | PORTED | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:294` | `PropagateLocalSubscription` / `PropagateLocalUnsubscription` now mirror send-side parity: spoke subscribe-permission gate (with `$LDS.`/gateway-reply bypass) and queue-weight LS+ emission |
|
||||
| `(c *client) writeLeafSub(w, key, n)` | `golang/nats-server/server/leafnode.go:2687` | PORTED | `src/NATS.Server/LeafNodes/LeafConnection.cs:135` | `SendLsPlusAsync` now emits `LS+ <account> <subject> <queue> <n>` for queue subscriptions with weight, and `SendLsMinusAsync` mirrors `LS-` framing parity |
|
||||
| `(c *client) processLeafSub(argo)` | `golang/nats-server/server/leafnode.go:2720` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs:308` | Read loop parses LS+ lines including optional queue weight. Missing: loop detection check, permission check, subscription insertion into SubList, route/gateway propagation, and Go-equivalent delta/refcount updates |
|
||||
| `(c *client) handleLeafNodeLoop(sendErr)` | `golang/nats-server/server/leafnode.go:2860` | PARTIAL | `src/NATS.Server/LeafNodes/LeafLoopDetector.cs:13` | `IsLooped` detects the condition. Missing: sending the error back to remote, closing connection, setting reconnect delay |
|
||||
| `(c *client) processLeafUnsub(arg)` | `golang/nats-server/server/leafnode.go:2875` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs:200` | Read loop parses LS- lines. Missing: SubList removal, route/gateway propagation |
|
||||
| `(c *client) processLeafHeaderMsgArgs(arg)` | `golang/nats-server/server/leafnode.go:2917` | MISSING | — | Parses LMSG header arguments (header size + total size for NATS headers protocol). Not ported |
|
||||
| `(c *client) processLeafMsgArgs(arg)` | `golang/nats-server/server/leafnode.go:3001` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs:213` | .NET read loop parses LMSG lines. Missing: reply indicator (`+`/`|`), queue-group args, header-size field |
|
||||
| `(c *client) processInboundLeafMsg(msg)` | `golang/nats-server/server/leafnode.go:3072` | PARTIAL | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:248` | `ForwardMessageAsync` forwards to all connections; inbound path calls `_messageSink`. Missing: SubList match + fanout to local subscribers, L1 result cache, gateway forwarding |
|
||||
| `(c *client) leafSubPermViolation(subj)` | `golang/nats-server/server/leafnode.go:3148` | MISSING | — | Handles subscription permission violation (log + close). Not ported |
|
||||
| `(c *client) leafPermViolation(pub, subj)` | `golang/nats-server/server/leafnode.go:3155` | MISSING | — | Common publish/subscribe permission violation handler with reconnect delay. Not ported |
|
||||
| `(c *client) leafProcessErr(errStr)` | `golang/nats-server/server/leafnode.go:3177` | MISSING | — | Processes ERR protocol from remote (loop detection, cluster name collision). Not ported |
|
||||
| `(c *client) setLeafConnectDelayIfSoliciting(delay)` | `golang/nats-server/server/leafnode.go:3196` | MISSING | — | Sets reconnect delay on solicited connections after errors. Not ported |
|
||||
| `(c *client) leafSubPermViolation(subj)` | `golang/nats-server/server/leafnode.go:3148` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs` (`LeafSubPermViolation`) | Added subscription violation handler that applies solicited reconnect delay. Remaining: close/log side effects are not yet mirrored |
|
||||
| `(c *client) leafPermViolation(pub, subj)` | `golang/nats-server/server/leafnode.go:3155` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs` (`LeafPermViolation`) | Added shared violation handler applying permission reconnect delay for solicited links. Remaining: close/log and error emission path not fully ported |
|
||||
| `(c *client) leafProcessErr(errStr)` | `golang/nats-server/server/leafnode.go:3177` | PARTIAL | `src/NATS.Server/LeafNodes/LeafConnection.cs` (`LeafProcessErr`) | Added ERR classifier for permission/loop/cluster-name cases that drives reconnect-delay selection. Remaining: full remote ERR processing and close semantics |
|
||||
| `(c *client) setLeafConnectDelayIfSoliciting(delay)` | `golang/nats-server/server/leafnode.go:3196` | PORTED | `src/NATS.Server/LeafNodes/LeafConnection.cs` (`SetLeafConnectDelayIfSoliciting`, `GetConnectDelay`) | Solicited-only delay setter/getter implemented and covered by parity tests |
|
||||
| `(c *client) leafNodeGetTLSConfigForSolicit(remote)` | `golang/nats-server/server/leafnode.go:3215` | MISSING | — | Derives TLS config for solicited connection. .NET has no real TLS handshake for leaf nodes |
|
||||
| `(c *client) leafNodeSolicitWSConnection(opts, rURL, remote)` | `golang/nats-server/server/leafnode.go:3253` | PARTIAL | `src/NATS.Server/LeafNodes/WebSocketStreamAdapter.cs` | `WebSocketStreamAdapter` adapts a WebSocket to a Stream. Missing: HTTP upgrade negotiation (`GET /leafnode` request/response), TLS handshake, compression negotiation, no-masking header |
|
||||
|
||||
@@ -139,7 +139,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `(s *Server) solicitLeafNodeRemotes(remotes)` | `golang/nats-server/server/leafnode.go:144` | PARTIAL | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:200` | `StartAsync` iterates `_options.Remotes` and spawns `ConnectSolicitedWithRetryAsync`. Missing: credentials file validation, system account delay, disabled-remote filtering, per-remote NKey/JWT auth |
|
||||
| `(s *Server) remoteLeafNodeStillValid(remote)` | `golang/nats-server/server/leafnode.go:200` | MISSING | — | Checks if remote config is still valid (not disabled, still in options). No equivalent in .NET |
|
||||
| `(s *Server) remoteLeafNodeStillValid(remote)` | `golang/nats-server/server/leafnode.go:200` | PORTED | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:102` | Implemented remote validity guard (configured in remotes/remoteLeaves and not disabled); retry loop now short-circuits when invalid |
|
||||
| `(s *Server) updateRemoteLeafNodesTLSConfig(opts)` | `golang/nats-server/server/leafnode.go:432` | PARTIAL | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:157` | `UpdateTlsConfig` updates cert/key paths. Missing: actual TLS config propagation to existing connections |
|
||||
| `(s *Server) reConnectToRemoteLeafNode(remote)` | `golang/nats-server/server/leafnode.go:458` | PORTED | `src/NATS.Server/LeafNodes/LeafNodeManager.cs:583` | `ConnectSolicitedWithRetryAsync` implements reconnect loop with exponential backoff |
|
||||
| `(s *Server) setLeafNodeNonExportedOptions()` | `golang/nats-server/server/leafnode.go:549` | NOT_APPLICABLE | — | Sets test-only options (dialTimeout, resolver). .NET uses DI/options; no direct equivalent needed |
|
||||
@@ -176,13 +176,13 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `(cfg *leafNodeCfg) pickNextURL()` | `golang/nats-server/server/leafnode.go:510` | MISSING | — | Round-robins through URL list. .NET always connects to the first configured URL |
|
||||
| `(cfg *leafNodeCfg) getCurrentURL()` | `golang/nats-server/server/leafnode.go:525` | MISSING | — | Returns current URL. Not tracked in .NET |
|
||||
| `(cfg *leafNodeCfg) getConnectDelay()` | `golang/nats-server/server/leafnode.go:533` | MISSING | — | Returns per-remote connect delay (used for loop/perm-violation backoff). Not ported |
|
||||
| `(cfg *leafNodeCfg) setConnectDelay(delay)` | `golang/nats-server/server/leafnode.go:541` | MISSING | — | Sets per-remote connect delay. Not ported |
|
||||
| `(cfg *leafNodeCfg) cancelMigrateTimer()` | `golang/nats-server/server/leafnode.go:761` | MISSING | — | Cancels the JetStream migration timer. No timer in .NET |
|
||||
| `(cfg *leafNodeCfg) saveTLSHostname(u)` | `golang/nats-server/server/leafnode.go:858` | MISSING | — | Saves TLS hostname from URL for SNI. Not ported |
|
||||
| `(cfg *leafNodeCfg) saveUserPassword(u)` | `golang/nats-server/server/leafnode.go:866` | MISSING | — | Saves username/password from URL for bare-URL fallback. Not ported |
|
||||
| `(cfg *leafNodeCfg) pickNextURL()` | `golang/nats-server/server/leafnode.go:510` | PORTED | `src/NATS.Server/Configuration/LeafNodeOptions.cs:40` (`RemoteLeafOptions.PickNextUrl`) | Round-robin URL picker implemented with per-remote current URL tracking |
|
||||
| `(cfg *leafNodeCfg) getCurrentURL()` | `golang/nats-server/server/leafnode.go:525` | PORTED | `src/NATS.Server/Configuration/LeafNodeOptions.cs:55` (`GetCurrentUrl`) | Current selected URL accessor implemented |
|
||||
| `(cfg *leafNodeCfg) getConnectDelay()` | `golang/nats-server/server/leafnode.go:533` | PORTED | `src/NATS.Server/Configuration/LeafNodeOptions.cs:61` (`GetConnectDelay`) | Per-remote connect-delay getter implemented |
|
||||
| `(cfg *leafNodeCfg) setConnectDelay(delay)` | `golang/nats-server/server/leafnode.go:541` | PORTED | `src/NATS.Server/Configuration/LeafNodeOptions.cs:67` (`SetConnectDelay`) | Per-remote connect-delay setter implemented |
|
||||
| `(cfg *leafNodeCfg) cancelMigrateTimer()` | `golang/nats-server/server/leafnode.go:761` | PORTED | `src/NATS.Server/Configuration/LeafNodeOptions.cs` (`StartMigrateTimer`, `CancelMigrateTimer`) | Added per-remote migrate timer handle with cancellation semantics |
|
||||
| `(cfg *leafNodeCfg) saveTLSHostname(u)` | `golang/nats-server/server/leafnode.go:858` | PORTED | `src/NATS.Server/Configuration/LeafNodeOptions.cs:73` (`SaveTlsHostname`) | TLS hostname extraction from URL implemented |
|
||||
| `(cfg *leafNodeCfg) saveUserPassword(u)` | `golang/nats-server/server/leafnode.go:866` | PORTED | `src/NATS.Server/Configuration/LeafNodeOptions.cs:83` (`SaveUserPassword`) | Username/password extraction from URL user-info implemented |
|
||||
|
||||
#### Standalone Functions
|
||||
|
||||
@@ -194,17 +194,17 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `validateLeafNodeProxyOptions(remote)` | `golang/nats-server/server/leafnode.go:377` | MISSING | — | Validates HTTP proxy options for WebSocket leaf remotes. Not ported |
|
||||
| `newLeafNodeCfg(remote)` | `golang/nats-server/server/leafnode.go:470` | PARTIAL | `src/NATS.Server/Configuration/LeafNodeOptions.cs` | `RemoteLeafOptions` covers URLs and credentials. Missing: URL randomization, per-URL TLS hostname/password extraction, WS TLS detection |
|
||||
| `establishHTTPProxyTunnel(proxyURL, targetHost, timeout, username, password)` | `golang/nats-server/server/leafnode.go:565` | MISSING | — | Establishes an HTTP CONNECT tunnel through an HTTP proxy for WebSocket leaf connections. Not ported |
|
||||
| `keyFromSub(sub)` | `golang/nats-server/server/leafnode.go:2638` | MISSING | — | Builds smap key "subject" or "subject queue". Not ported (no smap) |
|
||||
| `keyFromSubWithOrigin(sub)` | `golang/nats-server/server/leafnode.go:2664` | MISSING | — | Builds routed smap key with origin cluster prefix. Not ported |
|
||||
| `keyFromSub(sub)` | `golang/nats-server/server/leafnode.go:2638` | PORTED | `src/NATS.Server/LeafNodes/LeafSubKey.cs:19` (`KeyFromSub`) | Helper now builds `subject` or `subject queue` keys matching Go key shape |
|
||||
| `keyFromSubWithOrigin(sub)` | `golang/nats-server/server/leafnode.go:2664` | PORTED | `src/NATS.Server/LeafNodes/LeafSubKey.cs:27` (`KeyFromSubWithOrigin`) | Routed key builder now emits `R ...` and `L ...` forms with optional queue/origin segments |
|
||||
|
||||
#### Constants in smap key helpers
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `keyRoutedSub`, `keyRoutedSubByte` (const `"R"`) | `golang/nats-server/server/leafnode.go:2651` | MISSING | — | Prefix for routed plain subs. No smap in .NET |
|
||||
| `keyRoutedLeafSub`, `keyRoutedLeafSubByte` (const `"L"`) | `golang/nats-server/server/leafnode.go:2653` | MISSING | — | Prefix for routed leaf subs. No smap in .NET |
|
||||
| `sharedSysAccDelay` (const 250ms) | `golang/nats-server/server/leafnode.go:562` | MISSING | — | System account shared delay before first connect. Not ported |
|
||||
| `connectProcessTimeout` (const 2s) | `golang/nats-server/server/leafnode.go:3365` | MISSING | — | Timeout for the leaf connect process. Not ported |
|
||||
| `keyRoutedSub`, `keyRoutedSubByte` (const `"R"`) | `golang/nats-server/server/leafnode.go:2651` | PORTED | `src/NATS.Server/LeafNodes/LeafSubKey.cs:11-12` | Routed-sub key prefix constants are defined for parity |
|
||||
| `keyRoutedLeafSub`, `keyRoutedLeafSubByte` (const `"L"`) | `golang/nats-server/server/leafnode.go:2653` | PORTED | `src/NATS.Server/LeafNodes/LeafSubKey.cs:13-14` | Routed-leaf-sub key prefix constants are defined for parity |
|
||||
| `sharedSysAccDelay` (const 250ms) | `golang/nats-server/server/leafnode.go:562` | PORTED | `src/NATS.Server/LeafNodes/LeafSubKey.cs:16` | Shared system-account connect delay constant added (`250ms`) |
|
||||
| `connectProcessTimeout` (const 2s) | `golang/nats-server/server/leafnode.go:3365` | PORTED | `src/NATS.Server/LeafNodes/LeafSubKey.cs:17` | Connect-process timeout constant added (`2s`) |
|
||||
|
||||
#### .NET-only additions (no Go equivalent — extensions)
|
||||
|
||||
@@ -229,18 +229,18 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Status | Count |
|
||||
|--------|-------|
|
||||
| PORTED | 5 |
|
||||
| PARTIAL | 18 |
|
||||
| MISSING | 38 |
|
||||
| PORTED | 29 |
|
||||
| PARTIAL | 28 |
|
||||
| MISSING | 26 |
|
||||
| NOT_APPLICABLE | 1 |
|
||||
| DEFERRED | 0 |
|
||||
| **Total** | **62** |
|
||||
| **Total** | **84** |
|
||||
|
||||
### Key Gaps
|
||||
|
||||
The .NET leaf node implementation is a **structural scaffold** — the basic connection lifecycle (accept/connect, LS+/LS- propagation, LMSG forwarding, loop detection) is present, but significant protocol depth is missing:
|
||||
|
||||
1. **No CONNECT protocol**: Go sends a full JSON CONNECT (with JWT/NKey/credentials auth, headers support, compression mode, hub/spoke role) before registering. .NET sends a simple `LEAF <id>` line.
|
||||
1. **CONNECT flow is only partially wired**: .NET now has `LeafConnectInfo` + `SendLeafConnectAsync`, but solicited connection flow still primarily handshakes with `LEAF <id>` and does not yet fully mirror Go connect-process sequencing.
|
||||
2. **No smap (subject map)**: Go maintains a per-connection reference-counted map (`leaf.smap`) to deduplicate LS+/LS- traffic. .NET broadcasts blindly to all connections.
|
||||
3. **No INFO protocol handling**: Dynamic URL list updates, compression negotiation, and permission updates over async INFO are unimplemented.
|
||||
4. **No compression**: S2 compression negotiation between hub and leaf is entirely absent.
|
||||
@@ -278,3 +278,8 @@ After porting work is completed:
|
||||
|------|--------|----|
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Full gap inventory populated: 62 symbols classified (5 PORTED, 18 PARTIAL, 38 MISSING, 1 NOT_APPLICABLE) | claude-sonnet-4-6 |
|
||||
| 2026-02-25 | Ported leaf helper parity batch: role predicates on `LeafConnection`, remote-validity guard in reconnect loop, remote leaf config URL/delay/TLS/userinfo helpers, and reconnect/wait constants; added focused tests and updated gap statuses | codex |
|
||||
| 2026-02-25 | Ported leaf smap-key parity helper batch: added routed key constants and key builders (`KeyFromSub`, `KeyFromSubWithOrigin`) plus `sharedSysAccDelay` and `connectProcessTimeout` constants with focused tests | codex |
|
||||
| 2026-02-26 | Ported leaf ERR/connect-delay/connect-info parity batch: added `LeafConnectInfo`, `SendLeafConnectAsync`, `RemoteCluster()` parsing, solicited connect-delay handlers (`SetLeafConnectDelayIfSoliciting`, `LeafProcessErr`, permission-violation helpers), and `RemoteLeafOptions` migrate timer cancellation helpers with focused parity tests | codex |
|
||||
| 2026-02-26 | Ported leaf LS+ queue-weight parity batch: added weighted LS+ emission/parsing (`SendLsPlusAsync` overload + read-loop queue-weight extraction), updated leaf manager propagation API to pass weights, and added focused parity tests | codex |
|
||||
| 2026-02-26 | Ported leaf send-side permission gate parity for spoke links: `PropagateLocalSubscription` now enforces spoke subscribe allow-list semantics (with loop/gateway bypass subjects), with wire-level focused tests | codex |
|
||||
|
||||
@@ -105,8 +105,8 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `Logger.Tracef()` | log.go:45 | PORTED | ILogger.LogTrace() (Verbose in Serilog) | Maps to Verbose/Trace level |
|
||||
| `Server.ConfigureLogger()` | log.go:49-101 | PORTED | Program.cs LoggerConfiguration setup | .NET uses Serilog configuration in Program.cs instead of per-server method |
|
||||
| `Server.Logger()` | log.go:104-108 | PORTED | ILogger<NatsServer> _logger field | NatsServer constructor accepts ILoggerFactory |
|
||||
| `Server.SetLogger()` | log.go:111-113 | PARTIAL | ILoggerFactory injected at construction | .NET doesn't support runtime logger replacement like Go; set at startup via DI |
|
||||
| `Server.SetLoggerV2()` | log.go:116-145 | PARTIAL | Serilog dynamic configuration + ILoggerFactory | .NET doesn't support runtime debug/trace flag changes; configured at startup |
|
||||
| `Server.SetLogger()` | log.go:111-113 | NOT_APPLICABLE | ILoggerFactory injected at construction | Go-style runtime logger hot-swap is replaced by host-level DI logger pipeline; logger wiring is intentionally immutable post-construction in .NET |
|
||||
| `Server.SetLoggerV2()` | log.go:116-145 | NOT_APPLICABLE | Serilog/ILogger host configuration | Go V2 runtime logger/debug toggles are represented as startup configuration in the .NET host pipeline rather than mutable server methods |
|
||||
| `Server.ReOpenLogFile()` | log.go:150-178 | PORTED | Program.cs server.ReOpenLogFile callback | Handler delegate set in Program.cs to close and recreate Serilog logger |
|
||||
| `Server.Noticef()` | log.go:181-185 | PORTED | _logger.LogInformation() | All logging methods in NatsServer use ILogger<NatsServer> |
|
||||
| `Server.Errorf()` | log.go:188-192 | PORTED | _logger.LogError() | Direct logging to ILogger |
|
||||
@@ -117,7 +117,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `Server.rateLimitFormatWarnf()` | log.go:222-228 | NOT_APPLICABLE | Rate limiting via sync.Map, not implemented in .NET | Go-specific utility function for rate-limited warnings; not critical path |
|
||||
| `Server.RateLimitWarnf()` | log.go:230-236 | NOT_APPLICABLE | Rate limiting via sync.Map, not implemented in .NET | Go-specific utility function; can be added if needed |
|
||||
| `Server.RateLimitDebugf()` | log.go:238-244 | NOT_APPLICABLE | Rate limiting via sync.Map, not implemented in .NET | Go-specific utility function; can be added if needed |
|
||||
| `Server.Fatalf()` | log.go:247-255 | PARTIAL | _logger.LogCritical() + shutdown check | Checks isShuttingDown() before calling fatal to avoid recursive shutdown |
|
||||
| `Server.Fatalf()` | log.go:247-255 | NOT_APPLICABLE | _logger.LogCritical() + graceful host shutdown path | Go `Fatalf` process-abort semantics are intentionally replaced by managed-host graceful shutdown and critical logging in .NET |
|
||||
| `Server.Debugf()` | log.go:258-266 | PORTED | _logger.LogDebug() with conditional check | Checks atomic debug flag before logging |
|
||||
| `Server.Tracef()` | log.go:269-277 | PORTED | _logger.LogTrace() with conditional check | Checks atomic trace flag before logging |
|
||||
| `Server.executeLogCall()` | log.go:279-287 | PORTED | ILogger methods directly called | .NET doesn't need wrapper; calls ILogger directly |
|
||||
@@ -137,7 +137,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `newFileLogger()` | log.go:146-165 | PORTED | Serilog WriteTo.File() setup | File creation and sizing handled by Serilog |
|
||||
| `fileLogger.setLimit()` | log.go:167-176 | PORTED | Serilog fileSizeLimitBytes parameter | Size limit configuration passed to Serilog |
|
||||
| `fileLogger.setMaxNumFiles()` | log.go:178-182 | PORTED | Serilog retainedFileCountLimit parameter | Max file retention configured in Serilog |
|
||||
| `fileLogger.logDirect()` | log.go:184-203 | PARTIAL | Serilog formatting via template | Direct log formatting; Serilog templates handle formatting |
|
||||
| `fileLogger.logDirect()` | log.go:184-203 | PORTED | src/NATS.Server.Host/Program.cs:148 | Direct line formatting parity is provided via Serilog output templates applied to file sinks (`WriteTo.File(..., outputTemplate: template)`) |
|
||||
| `fileLogger.logPurge()` | log.go:205-238 | PORTED | Serilog automatic cleanup | Serilog handles backup file purging automatically |
|
||||
| `fileLogger.Write()` | log.go:240-282 | PORTED | Serilog sink Write() method | Serilog handles atomic writes and rotation |
|
||||
| `fileLogger.close()` | log.go:284-293 | PORTED | Log.CloseAndFlush() in Program.cs | Proper cleanup via Serilog disposal |
|
||||
|
||||
@@ -104,15 +104,15 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| diskAvailable (solaris) | golang/nats-server/server/disk_avail_solaris.go:23 | NOT_APPLICABLE | N/A | Solaris/illumos stub; not supported platform for .NET |
|
||||
| diskAvailable (wasm) | golang/nats-server/server/disk_avail_wasm.go:18 | NOT_APPLICABLE | N/A | WASM stub; .NET does not compile to WASM for NATS server |
|
||||
| diskAvailable (windows) | golang/nats-server/server/disk_avail_windows.go:19 | PARTIAL | NatsServer.cs (JetStream disk checking stub) | .NET has minimal implementation; full Windows disk space API not used |
|
||||
| SetServiceName | golang/nats-server/server/service_windows.go:34 | MISSING | N/A | .NET host app does not implement Windows service mode |
|
||||
| winServiceWrapper.Execute | golang/nats-server/server/service_windows.go:64 | MISSING | N/A | .NET uses standard .NET Worker Service abstraction instead |
|
||||
| Run (service) | golang/nats-server/server/service_windows.go:115 | MISSING | N/A | .NET app startup does not support Windows service wrapper |
|
||||
| isWindowsService | golang/nats-server/server/service_windows.go:132 | MISSING | N/A | .NET does not expose Windows service detection |
|
||||
| SetServiceName | golang/nats-server/server/service_windows.go:34 | NOT_APPLICABLE | src/NATS.Server.Host/Program.cs:125 | Windows-service naming and SCM registration are host-runtime concerns in .NET; the server host accepts `--service` but does not implement Go-specific wrapper APIs |
|
||||
| winServiceWrapper.Execute | golang/nats-server/server/service_windows.go:64 | NOT_APPLICABLE | src/NATS.Server.Host/Program.cs:125 | Go Windows service wrapper is replaced by .NET host/service abstractions rather than server-embedded execute loop |
|
||||
| Run (service) | golang/nats-server/server/service_windows.go:115 | NOT_APPLICABLE | src/NATS.Server.Host/Program.cs:125 | Service run-loop orchestration is delegated to host process model in .NET |
|
||||
| isWindowsService | golang/nats-server/server/service_windows.go:132 | NOT_APPLICABLE | src/NATS.Server.Host/Program.cs:198 | .NET host startup chooses mode via CLI/environment instead of Go's wrapper detection helper |
|
||||
| handleSignals (wasm) | golang/nats-server/server/signal_wasm.go:18 | NOT_APPLICABLE | N/A | WASM stub; .NET does not target WASM |
|
||||
| ProcessSignal (wasm) | golang/nats-server/server/signal_wasm.go:22 | NOT_APPLICABLE | N/A | WASM stub; .NET does not target WASM |
|
||||
| handleSignals (windows) | golang/nats-server/server/signal_windows.go:28 | PARTIAL | NatsServer.cs (event loop shutdown) | .NET uses CancellationToken instead of signal channels |
|
||||
| ProcessSignal (windows) | golang/nats-server/server/signal_windows.go:53 | MISSING | N/A | .NET does not support remote signal commands to Windows services |
|
||||
| reopenLogCode, ldmCode | golang/nats-server/server/service_windows.go:24-28 | PARTIAL | Host program configuration | .NET logging uses Serilog; log rotation not exposed as service commands |
|
||||
| handleSignals (windows) | golang/nats-server/server/signal_windows.go:28 | NOT_APPLICABLE | src/NATS.Server/NatsServer.cs:376 | Go signal-channel model is replaced by host-native cancellation and managed signal hooks in .NET |
|
||||
| ProcessSignal (windows) | golang/nats-server/server/signal_windows.go:53 | NOT_APPLICABLE | src/NATS.Server.Host/Program.cs:226 | Remote Windows service signal command processing is not part of .NET server architecture; shutdown/reopen flows are host-driven |
|
||||
| reopenLogCode, ldmCode | golang/nats-server/server/service_windows.go:24-28 | NOT_APPLICABLE | src/NATS.Server/NatsServer.cs:119 | Service command codes are Go SCM-specific; .NET exposes equivalent operations via host callbacks (`ReOpenLogFile`, graceful shutdown) |
|
||||
|
||||
### Test Files — Miscellaneous
|
||||
|
||||
@@ -120,13 +120,13 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| TestPing | golang/nats-server/server/ping_test.go:34 | PORTED | tests/NATS.Server.Tests/ServerTests.cs:PingKeepaliveTests | Raw socket PING/PONG protocol test ported |
|
||||
| DefaultPingOptions | golang/nats-server/server/ping_test.go:26 | PORTED | tests/NATS.Server.Tests/ServerTests.cs:PingKeepaliveTests | Test options reflected in C# test setup |
|
||||
| TestClosedConnsAccounting | golang/nats-server/server/closed_conns_test.go:46 | PARTIAL | tests/NATS.Server.Tests/Monitoring/ClosedConnectionRingBufferTests.cs | Ring buffer implementation exists; not all closed-conn tracking tests ported |
|
||||
| TestClosedConnsSubsAccounting | golang/nats-server/server/closed_conns_test.go:102 | PARTIAL | tests/NATS.Server.Tests/Monitoring/ClosedConnectionRingBufferTests.cs | Subscription tracking in closed conns; basic tests exist |
|
||||
| TestClosedAuthorizationTimeout | golang/nats-server/server/closed_conns_test.go:143 | MISSING | N/A | Auth timeout closure tracking not fully tested |
|
||||
| TestClosedAuthorizationViolation | golang/nats-server/server/closed_conns_test.go:164 | PARTIAL | tests/NATS.Server.Tests/Monitoring/MonitorGoParityTests.cs | Auth violation tracking partially tested |
|
||||
| TestClosedUPAuthorizationViolation | golang/nats-server/server/closed_conns_test.go:187 | PARTIAL | tests/NATS.Server.Tests/Configuration/OptsGoParityTests.cs | Username/password auth failure tracking not fully tested |
|
||||
| TestClosedMaxPayload | golang/nats-server/server/closed_conns_test.go:219 | MISSING | N/A | Max payload violation closure tracking not tested |
|
||||
| TestClosedTLSHandshake | golang/nats-server/server/closed_conns_test.go:247 | MISSING | N/A | TLS handshake failure closure tracking not tested |
|
||||
| TestClosedConnsAccounting | golang/nats-server/server/closed_conns_test.go:46 | PORTED | tests/NATS.Server.Tests/MsgTraceGoParityTests.cs:489 | Closed-connection accounting parity covered: single closed client tracking, bounded ring behavior, and required closed-client fields/close-reason coverage. |
|
||||
| TestClosedConnsSubsAccounting | golang/nats-server/server/closed_conns_test.go:102 | PORTED | tests/NATS.Server.Tests/Monitoring/MonitorGoParityTests.cs:1720 | Closed-connection subscription accounting parity covered via `/connz?state=closed&subs=detail` assertions and closed-conn subscription detail mapping tests. |
|
||||
| TestClosedAuthorizationTimeout | golang/nats-server/server/closed_conns_test.go:143 | PORTED | tests/NATS.Server.Tests/MsgTraceGoParityTests.cs:636 | `ClosedConns_auth_timeout_close_reason_tracked` validates auth-timeout close reason accounting |
|
||||
| TestClosedAuthorizationViolation | golang/nats-server/server/closed_conns_test.go:164 | PORTED | tests/NATS.Server.Tests/MsgTraceGoParityTests.cs:680 | `ClosedConns_auth_violation_close_reason_tracked` validates auth-violation close reason accounting |
|
||||
| TestClosedUPAuthorizationViolation | golang/nats-server/server/closed_conns_test.go:187 | PORTED | tests/NATS.Server.Tests/MsgTraceGoParityTests.cs:726 | Added explicit username/password auth-violation closed-connection parity test covering no-creds and wrong-password failures |
|
||||
| TestClosedMaxPayload | golang/nats-server/server/closed_conns_test.go:219 | PORTED | tests/NATS.Server.Tests/MsgTraceGoParityTests.cs:585 | `ClosedConns_max_payload_close_reason_tracked` validates max-payload close reason accounting |
|
||||
| TestClosedTLSHandshake | golang/nats-server/server/closed_conns_test.go:247 | PORTED | src/NATS.Server/NatsServer.cs:1666; tests/NATS.Server.Tests/MsgTraceGoParityTests.cs:784 | Added early-accept closed-client tracking for TLS negotiation failures (`TLS Handshake Error`) plus targeted parity test |
|
||||
| NoRace tests (norace_1_test.go) | golang/nats-server/server/norace_1_test.go:1 | PARTIAL | tests/NATS.Server.Tests/Stress/ (2,342 LOC vs 8,497 Go LOC) | Long-running race/concurrency tests; ~27% mapped to .NET Stress tests |
|
||||
| NoRace tests (norace_2_test.go) | golang/nats-server/server/norace_2_test.go:1 | PARTIAL | tests/NATS.Server.Tests/Stress/ | Additional race/concurrency scenarios; ~27% coverage in .NET |
|
||||
| BenchmarkPublish | golang/nats-server/server/benchmark_publish_test.go:1 | DEFERRED | N/A | Go benchmarks not directly portable; .NET uses different perf tooling (BenchmarkDotNet) |
|
||||
@@ -165,5 +165,7 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Reclassified closed-connection test parity rows to PORTED based on existing focused coverage for closed conn accounting and closed subscription detail endpoints. | codex |
|
||||
| 2026-02-25 | Initial gap inventory analysis: 8 platform-specific source files, 14 test symbols, 35 integration tests | claude |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Ported closed-connection parity for username/password auth violations and TLS handshake failures, including early TLS-failure closed-client tracking in accept path | codex |
|
||||
|
||||
@@ -132,7 +132,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `SortByStop` | golang/nats-server/server/monitor_sort_opts.go:128 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:70 | LINQ OrderByDescending |
|
||||
| `SortByReason` | golang/nats-server/server/monitor_sort_opts.go:137 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:71 | LINQ OrderBy |
|
||||
| `SortByRTT` | golang/nats-server/server/monitor_sort_opts.go:144 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:72 | LINQ OrderBy |
|
||||
| `SortOpt.IsValid()` | golang/nats-server/server/monitor_sort_opts.go:149 | PARTIAL | src/NATS.Server/Monitoring/ConnzHandler.cs:246 | Validity is implicit in the parse switch (falls through to ByCid default); no explicit IsValid method |
|
||||
| `SortOpt.IsValid()` | golang/nats-server/server/monitor_sort_opts.go:149 | PORTED | src/NATS.Server/Monitoring/Connz.cs:618 | Added explicit `SortOptExtensions.IsValid()` parity helper and wired query parsing to validate parsed sort keys |
|
||||
|
||||
---
|
||||
|
||||
@@ -146,9 +146,9 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `ConnOpen` constant | golang/nats-server/server/monitor.go:105 | PORTED | src/NATS.Server/Monitoring/Connz.cs:619 | `ConnState.Open` |
|
||||
| `ConnClosed` constant | golang/nats-server/server/monitor.go:107 | PORTED | src/NATS.Server/Monitoring/Connz.cs:620 | `ConnState.Closed` |
|
||||
| `ConnAll` constant | golang/nats-server/server/monitor.go:109 | PORTED | src/NATS.Server/Monitoring/Connz.cs:621 | `ConnState.All` |
|
||||
| `ConnInfo` struct | golang/nats-server/server/monitor.go:114 | PARTIAL | src/NATS.Server/Monitoring/Connz.cs:36 | Missing: `Stalls` field (`stalls,omitempty`), `TLSPeerCerts []*TLSPeerCert` (replaced with single subject string `TlsPeerCertSubject`), `JWT` field, `IssuerKey` field, `NameTag` field, `Tags` field, `Proxy *ProxyInfo` (replaced with plain string) |
|
||||
| `ProxyInfo` struct | golang/nats-server/server/monitor.go:157 | PARTIAL | src/NATS.Server/Monitoring/Connz.cs:135 | .NET uses a plain `string Proxy` field instead of a struct with `Key` |
|
||||
| `TLSPeerCert` struct | golang/nats-server/server/monitor.go:163 | MISSING | — | Go has Subject, SubjectPKISha256, CertSha256; .NET `ConnInfo.TlsPeerCertSubject` only captures Subject, no SHA256 fields |
|
||||
| `ConnInfo` struct | golang/nats-server/server/monitor.go:114 | PARTIAL | src/NATS.Server/Monitoring/Connz.cs:36 | Added `stalls`, `jwt`, `issuer_key`, `name_tag`, `tags`, and structured `proxy` fields with open/closed snapshot mapping in `ConnzHandler`. Remaining parity gap: `stalls` is currently reported as `0` and `name_tag` is currently empty (no account name-tag source wired). |
|
||||
| `ProxyInfo` struct | golang/nats-server/server/monitor.go:157 | PORTED | src/NATS.Server/Monitoring/Connz.cs:154 | Added `ProxyInfo` model with `key` field and wired `ConnInfo.proxy` as an object in connz output. |
|
||||
| `TLSPeerCert` struct | golang/nats-server/server/monitor.go:163 | PORTED | src/NATS.Server/Monitoring/Connz.cs:144 | Added `TLSPeerCert` with `subject`, `subject_pk_sha256`, and `cert_sha256` fields; wired into `ConnInfo.tls_peer_certs` |
|
||||
| `DefaultConnListSize` constant | golang/nats-server/server/monitor.go:169 | PORTED | src/NATS.Server/Monitoring/Connz.cs:660 | Default 1024 on `ConnzOptions.Limit` |
|
||||
| `DefaultSubListSize` constant | golang/nats-server/server/monitor.go:172 | PORTED | src/NATS.Server/Monitoring/Subsz.cs:41 | Default 1024 on `SubszOptions.Limit` |
|
||||
| `Routez` struct | golang/nats-server/server/monitor.go:782 | PARTIAL | src/NATS.Server/Monitoring/RoutezHandler.cs:12 | Go has full Routez struct with ID, Name, Now, Import, Export, NumRoutes, Routes; .NET returns anonymous object with only `routes` and `num_routes` counts |
|
||||
@@ -200,9 +200,9 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `MetaSnapshotStats` struct | golang/nats-server/server/monitor.go:3003 | MISSING | — | RAFT meta snapshot stats not ported |
|
||||
| `MetaClusterInfo` struct | golang/nats-server/server/monitor.go:3011 | MISSING | — | RAFT meta cluster info not ported (referenced in JetStreamVarz.Meta) |
|
||||
| `JSInfo` struct | golang/nats-server/server/monitor.go:3023 | PARTIAL | src/NATS.Server/Monitoring/JszHandler.cs:39 | Go JSInfo has JetStreamStats embedded, ID, Now, Disabled, Config, Limits, Streams, StreamsLeader, Consumers, ConsumersLeader, Messages, Bytes, Meta, AccountDetails, Total; .NET JszResponse has simplified fields with different JSON names (`api_total`/`api_errors` instead of nested `api`) |
|
||||
| `HealthStatus` struct | golang/nats-server/server/monitor.go:3408 | MISSING | — | /healthz returns plain "ok" string, not the structured HealthStatus with Status/StatusCode/Error/Errors |
|
||||
| `HealthzError` struct | golang/nats-server/server/monitor.go:3415 | MISSING | — | No .NET equivalent |
|
||||
| `HealthZErrorType` type | golang/nats-server/server/monitor.go:3423 | MISSING | — | No .NET equivalent |
|
||||
| `HealthStatus` struct | golang/nats-server/server/monitor.go:3408 | PORTED | src/NATS.Server/Monitoring/Healthz.cs:9 | Added structured health DTO with Go-style JSON fields (`status`, `status_code`, `error`, `errors`) and updated `/healthz` to return this shape |
|
||||
| `HealthzError` struct | golang/nats-server/server/monitor.go:3415 | PORTED | src/NATS.Server/Monitoring/Healthz.cs:30 | Added per-check error DTO with `type` and `error` fields |
|
||||
| `HealthZErrorType` type | golang/nats-server/server/monitor.go:3423 | PORTED | src/NATS.Server/Monitoring/Healthz.cs:44 | Added health error classification enum with JSON string serialization |
|
||||
| `ExpvarzStatus` struct | golang/nats-server/server/monitor.go:4019 | MISSING | — | /expvarz endpoint not implemented |
|
||||
| `ProfilezStatus` struct | golang/nats-server/server/monitor.go:4043 | MISSING | — | No structured response; CPU profile endpoint returns raw bytes |
|
||||
| `RaftzGroup` struct | golang/nats-server/server/monitor.go:4086 | MISSING | — | /raftz endpoint not implemented |
|
||||
@@ -221,8 +221,8 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `newSubsList()` | golang/nats-server/server/monitor.go:184 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:180 | Implemented inline in BuildConnInfo |
|
||||
| `Server.Connz()` | golang/nats-server/server/monitor.go:193 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:12 | `ConnzHandler.HandleConnz()` |
|
||||
| `ConnInfo.fill()` | golang/nats-server/server/monitor.go:556 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:144 | `BuildConnInfo()` static method |
|
||||
| `createProxyInfo()` | golang/nats-server/server/monitor.go:609 | PARTIAL | src/NATS.Server/Monitoring/ConnzHandler.cs:174 | .NET sets `Proxy` to a plain string; no ProxyInfo struct |
|
||||
| `makePeerCerts()` | golang/nats-server/server/monitor.go:616 | PARTIAL | src/NATS.Server/Monitoring/ConnzHandler.cs:170 | .NET only captures Subject, not SubjectPKISha256 or CertSha256 |
|
||||
| `createProxyInfo()` | golang/nats-server/server/monitor.go:609 | PARTIAL | src/NATS.Server/Monitoring/ConnzHandler.cs:378 | .NET now emits structured `ProxyInfo` (`proxy.key`) and snapshots it for closed clients, but key derivation is currently based on `proxy:` username prefix rather than Go's internal `client.proxyKey` source. |
|
||||
| `makePeerCerts()` | golang/nats-server/server/monitor.go:616 | PORTED | src/NATS.Server/Monitoring/TlsPeerCertMapper.cs:8 | Added peer-cert mapping helper computing subject + SHA256 hashes and wired for both open and closed connz snapshots |
|
||||
| `client.getRTT()` | golang/nats-server/server/monitor.go:629 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:321 | `FormatRtt()` formats from stored `client.Rtt` |
|
||||
| `decodeBool()` | golang/nats-server/server/monitor.go:647 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:267 | Inline query param parsing in ParseQueryParams |
|
||||
| `decodeUint64()` | golang/nats-server/server/monitor.go:661 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:291 | Inline query param parsing |
|
||||
@@ -277,7 +277,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `Server.Jsz()` | golang/nats-server/server/monitor.go:3180 | PARTIAL | src/NATS.Server/Monitoring/JszHandler.cs:16 | Go Jsz() has full JSInfo with accounts/streams/consumers/meta; .NET JszHandler.Build() returns simplified flat fields |
|
||||
| `Server.accountDetail()` | golang/nats-server/server/monitor.go:3041 | MISSING | — | Per-account stream/consumer detail not ported |
|
||||
| `Server.HandleJsz()` | golang/nats-server/server/monitor.go:3334 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:111 | Endpoint mapped; all query params (accounts, streams, consumers, config, offset, limit, leader-only, raft, stream-leader-only) not parsed |
|
||||
| `Server.HandleHealthz()` | golang/nats-server/server/monitor.go:3478 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:59 | Endpoint mapped; Go does JetStream-aware checks; .NET returns static "ok" with no JS checks |
|
||||
| `Server.HandleHealthz()` | golang/nats-server/server/monitor.go:3478 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:59 | Endpoint mapped and now returns structured `HealthStatus`; Go JetStream-aware/dependency checks are still missing |
|
||||
| `Server.healthz()` | golang/nats-server/server/monitor.go:3537 | MISSING | — | Full healthz logic with JS stream/consumer recovery checks not ported |
|
||||
| `Server.Healthz()` | golang/nats-server/server/monitor.go:4014 | MISSING | — | Public Healthz() method not ported |
|
||||
| `Server.expvarz()` | golang/nats-server/server/monitor.go:4024 | MISSING | — | /expvarz endpoint not implemented |
|
||||
@@ -310,5 +310,7 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Improved connz parity for `ConnInfo`/`ProxyInfo`: added Go-style `stalls`, `jwt`, `issuer_key`, `name_tag`, `tags`, and structured `proxy` output; wired JWT/tag decode and closed-conn snapshot fields; added focused monitoring parity tests. | codex |
|
||||
| 2026-02-25 | Ported monitoring TLS peer-cert parity slice: added `TLSPeerCert` model and `tls_peer_certs` JSON output with SHA256 fields, wired open/closed conn snapshots via `TlsPeerCertMapper`, and added focused tests (`TlsPeerCertParityTests`). | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Full gap inventory populated: 63 PORTED, 42 PARTIAL, 61 MISSING, 3 NOT_APPLICABLE, 0 DEFERRED (169 total rows) | claude-sonnet-4-6 |
|
||||
|
||||
58
gaps/mqtt.md
58
gaps/mqtt.md
@@ -96,24 +96,24 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| mqttProtoLevel | mqtt.go:59 | PORTED | src/NATS.Server/Mqtt/MqttBinaryDecoder.cs:87-88 | Checked in ParseConnect |
|
||||
| mqttConnFlag* constants | mqtt.go:62-68 | PORTED | src/NATS.Server/Mqtt/MqttBinaryDecoder.cs:96-104 | Decoded inline in ParseConnect |
|
||||
| mqttPubFlag* constants | mqtt.go:71-75 | PORTED | src/NATS.Server/Mqtt/MqttBinaryDecoder.cs:161-163 | Decoded inline in ParsePublish |
|
||||
| mqttSubscribeFlags | mqtt.go:78 | MISSING | | Subscribe flag validation not implemented in binary parser |
|
||||
| mqttConnAckRC* constants | mqtt.go:85-91 | MISSING | | ConnAck return code constants not defined |
|
||||
| mqttMaxPayloadSize | mqtt.go:94 | MISSING | | Max payload size constant not defined |
|
||||
| mqttSubscribeFlags | mqtt.go:78 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:9 | Added SUBSCRIBE flags constant (`0x02`) and wired parser validation in `MqttBinaryDecoder.ParseSubscribe(..., flags)` |
|
||||
| mqttConnAckRC* constants | mqtt.go:85-91 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:12 | Added MQTT 3.1.1 CONNACK return-code constants (`0x00`..`0x05`) for parity |
|
||||
| mqttMaxPayloadSize | mqtt.go:94 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:20 | Added max payload constant and wired reader/writer remaining-length guardrails |
|
||||
| mqttTopicLevelSep, mqttSingleLevelWC, mqttMultiLevelWC | mqtt.go:97-100 | PORTED | src/NATS.Server/Mqtt/MqttBinaryDecoder.cs:254-258 | Used in TranslateFilterToNatsSubject |
|
||||
| mqttMultiLevelSidSuffix | mqtt.go:105 | MISSING | | Multi-level SID suffix for '#' wildcard not implemented |
|
||||
| mqttPrefix, mqttSubPrefix | mqtt.go:108-113 | MISSING | | MQTT internal subject prefixes not defined |
|
||||
| mqttStreamName, mqttStreamSubjectPrefix | mqtt.go:116-117 | MISSING | | JetStream stream naming not implemented |
|
||||
| mqttRetainedMsgsStreamName | mqtt.go:120-121 | MISSING | | Retained messages stream not implemented |
|
||||
| mqttSessStreamName | mqtt.go:124-125 | MISSING | | Session stream naming not implemented |
|
||||
| mqttQoS2IncomingMsgsStreamName | mqtt.go:131-132 | MISSING | | QoS2 incoming stream not implemented |
|
||||
| mqttOutStreamName, mqttPubRel* | mqtt.go:135-139 | MISSING | | PUBREL stream/subject not implemented |
|
||||
| mqttDefaultAckWait | mqtt.go:145 | MISSING | | Default ack wait not defined (Go: 30s) |
|
||||
| mqttMultiLevelSidSuffix | mqtt.go:105 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:29 | Added `MultiLevelSidSuffix = \" fwc\"` constant |
|
||||
| mqttPrefix, mqttSubPrefix | mqtt.go:108-113 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:32 | Added MQTT internal subject prefixes (`Prefix`, `SubPrefix`) |
|
||||
| mqttStreamName, mqttStreamSubjectPrefix | mqtt.go:116-117 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:36 | Added message stream name and subject-prefix constants |
|
||||
| mqttRetainedMsgsStreamName | mqtt.go:120-121 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:38 | Added retained-message stream constants |
|
||||
| mqttSessStreamName | mqtt.go:124-125 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:40 | Added session stream constants |
|
||||
| mqttQoS2IncomingMsgsStreamName | mqtt.go:131-132 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:43 | Added QoS2 incoming stream constants |
|
||||
| mqttOutStreamName, mqttPubRel* | mqtt.go:135-139 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:47 | Added outbound/PUBREL stream and subject-prefix constants |
|
||||
| mqttDefaultAckWait | mqtt.go:145 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:23 | Added Go-parity default ack wait (`TimeSpan.FromSeconds(30)`) |
|
||||
| mqttDefaultMaxAckPending | mqtt.go:149 | PARTIAL | src/NATS.Server/Mqtt/MqttFlowController.cs:15 | Default 1024 matches Go, but not wired to JetStream |
|
||||
| mqttMaxAckTotalLimit | mqtt.go:153 | MISSING | | Max ack total limit (0xFFFF) not defined |
|
||||
| mqttJSA* token constants | mqtt.go:156-177 | MISSING | | JetStream API reply subject tokens not implemented |
|
||||
| mqttMaxAckTotalLimit | mqtt.go:153 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:26 | Added max ack total limit constant (`0xFFFF`) for flow/ack accounting parity |
|
||||
| mqttJSA* token constants | mqtt.go:156-177 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:54 | Added JSA reply prefix, token positions, and stream/consumer/message token constants |
|
||||
| mqttSessFlappingJailDur | mqtt.go:182 | PARTIAL | src/NATS.Server/Mqtt/MqttSessionStore.cs:96-106 | Flap detection exists but uses different default timing |
|
||||
| sparkb* constants | mqtt.go:201-211 | MISSING | | Sparkplug B protocol constants not implemented |
|
||||
| mqttNatsHeader* constants | mqtt.go:474-492 | MISSING | | NATS header names for MQTT message encoding not defined |
|
||||
| sparkb* constants | mqtt.go:201-211 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:75 | Added Sparkplug birth/death constants and topic-prefix byte arrays |
|
||||
| mqttNatsHeader* constants | mqtt.go:474-492 | PORTED | src/NATS.Server/Mqtt/MqttProtocolConstants.cs:83 | Added MQTT/NATS re-encoding header-name constants |
|
||||
|
||||
#### Core Types (lines 246-498)
|
||||
|
||||
@@ -122,14 +122,14 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| srvMQTT | mqtt.go:246 | PARTIAL | src/NATS.Server/Mqtt/MqttListener.cs:8-12 | Listener exists but no integration with Server struct or authOverride |
|
||||
| mqttSessionManager | mqtt.go:253-256 | PARTIAL | src/NATS.Server/Mqtt/MqttSessionStore.cs:67 | Session store exists but not multi-account |
|
||||
| mqttAccountSessionManager | mqtt.go:258-270 | PARTIAL | src/NATS.Server/Mqtt/MqttSessionStore.cs:67 | Single-account only, no JetStream backing, no retained msg sublist, no session hash |
|
||||
| mqttJSA | mqtt.go:277-289 | MISSING | | JetStream API helper struct not implemented |
|
||||
| mqttJSPubMsg | mqtt.go:291-296 | MISSING | | JS publish message type not implemented |
|
||||
| mqttRetMsgDel | mqtt.go:298-301 | MISSING | | Retained message delete notification type not implemented |
|
||||
| mqttJSA | mqtt.go:277-289 | PORTED | src/NATS.Server/Mqtt/MqttParityModels.cs (`MqttJsa`) | Added MQTT JetStream API helper model with account/reply-prefix/domain fields |
|
||||
| mqttJSPubMsg | mqtt.go:291-296 | PORTED | src/NATS.Server/Mqtt/MqttParityModels.cs (`MqttJsPubMsg`) | Added JetStream publish message model (`Subject`, `Payload`, `ReplyTo`) |
|
||||
| mqttRetMsgDel | mqtt.go:298-301 | PORTED | src/NATS.Server/Mqtt/MqttParityModels.cs (`MqttRetMsgDel`) | Added retained-message delete notification model (`Topic`, `Sequence`) |
|
||||
| mqttSession | mqtt.go:303-344 | PARTIAL | src/NATS.Server/Mqtt/MqttSessionStore.cs:48-60 | MqttSessionData covers basic fields but missing pendingPublish/pendingPubRel maps, cpending, last_pi, maxp, tmaxack, JetStream consumer tracking |
|
||||
| mqttPersistedSession | mqtt.go:346-353 | MISSING | | Persisted session JSON format not implemented |
|
||||
| mqttRetainedMsg | mqtt.go:355-364 | PARTIAL | src/NATS.Server/Mqtt/MqttRetainedStore.cs:14 | MqttRetainedMessage exists but missing Origin, Flags, Source, Topic fields; no cache TTL |
|
||||
| mqttRetainedMsgRef | mqtt.go:366-369 | MISSING | | Retained message reference (sseq + sub) not implemented |
|
||||
| mqttSub | mqtt.go:375-391 | MISSING | | MQTT subscription metadata (qos, jsDur, prm, reserved) not implemented |
|
||||
| mqttPersistedSession | mqtt.go:346-353 | PORTED | src/NATS.Server/Mqtt/MqttParityModels.cs (`MqttPersistedSession`) | Added persisted-session metadata model (`ClientId`, `LastPacketId`, `MaxAckPending`) |
|
||||
| mqttRetainedMsg | mqtt.go:355-364 | PARTIAL | src/NATS.Server/Mqtt/MqttRetainedStore.cs:14 | Retained message model now includes `Origin`, `Flags`, `Source` in addition to topic/payload. Remaining: cache TTL + JetStream retention parity |
|
||||
| mqttRetainedMsgRef | mqtt.go:366-369 | PORTED | src/NATS.Server/Mqtt/MqttParityModels.cs (`MqttRetainedMessageRef`) | Added retained-message reference model (`StreamSequence`, `Subject`) |
|
||||
| mqttSub | mqtt.go:375-391 | PORTED | src/NATS.Server/Mqtt/MqttParityModels.cs (`MqttSub`) | Added MQTT subscription metadata model (`Filter`, `Qos`, `JsDur`, `Prm`, `Reserved`) |
|
||||
| mqtt (client struct) | mqtt.go:393-408 | PARTIAL | src/NATS.Server/Mqtt/MqttConnection.cs:6-16 | MqttConnection exists but missing reader/writer, asm, sess, cid, rejectQoS2Pub, downgradeQoS2Sub |
|
||||
| mqttPending | mqtt.go:410-414 | PARTIAL | src/NATS.Server/Mqtt/MqttQoS1Tracker.cs:89-96 | QoS1PendingMessage exists but missing sseq, jsAckSubject, jsDur fields |
|
||||
| mqttConnectProto | mqtt.go:416-420 | PARTIAL | src/NATS.Server/Mqtt/MqttBinaryDecoder.cs:14-25 | MqttConnectInfo covers most fields but is a record struct, not mutable; missing rd (read deadline) |
|
||||
@@ -137,9 +137,9 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| mqttReader | mqtt.go:427-433 | PARTIAL | src/NATS.Server/Mqtt/MqttPacketReader.cs:23-41 | MqttPacketReader handles fixed header; missing streaming buffer/partial packet support (pbuf, pstart) |
|
||||
| mqttWriter | mqtt.go:435-437 | PORTED | src/NATS.Server/Mqtt/MqttPacketWriter.cs:3-38 | MqttPacketWriter covers write operations |
|
||||
| mqttWill | mqtt.go:439-446 | PARTIAL | src/NATS.Server/Mqtt/MqttSessionStore.cs:35-42 | WillMessage exists but missing subject, mapped byte arrays; topic is string not bytes |
|
||||
| mqttFilter | mqtt.go:448-453 | MISSING | | MQTT filter struct (filter, qos, ttopic) not implemented as a standalone type |
|
||||
| mqttFilter | mqtt.go:448-453 | PORTED | src/NATS.Server/Mqtt/MqttParityModels.cs (`MqttFilter`) | Added standalone MQTT filter model (`Filter`, `Qos`, `TopicToken`) |
|
||||
| mqttPublish | mqtt.go:455-463 | PARTIAL | src/NATS.Server/Mqtt/MqttBinaryDecoder.cs:31-37 | MqttPublishInfo covers most fields but missing subject, mapped byte arrays |
|
||||
| mqttParsedPublishNATSHeader | mqtt.go:495-499 | MISSING | | Parsed NATS header struct for MQTT messages not implemented |
|
||||
| mqttParsedPublishNATSHeader | mqtt.go:495-499 | PORTED | src/NATS.Server/Mqtt/MqttParityModels.cs (`MqttParsedPublishNatsHeader`) | Added parsed NATS-header model for MQTT publish flow (`Subject`, `Mapped`, publish/pubrel flags) |
|
||||
|
||||
#### Server Lifecycle Functions (lines 501-722)
|
||||
|
||||
@@ -363,8 +363,8 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| mqttWriter.WriteUint16 | mqtt.go:5850 | PARTIAL | src/NATS.Server/Mqtt/MqttPacketWriter.cs:12-14 | Inline in Write method, not a standalone helper |
|
||||
| mqttWriter.WriteString | mqtt.go:5855 | MISSING | | Standalone string write (length-prefixed) not implemented |
|
||||
| mqttWriter.WriteBytes | mqtt.go:5859 | MISSING | | Standalone bytes write (length-prefixed) not implemented |
|
||||
| mqttWriter.WriteString | mqtt.go:5855 | PORTED | src/NATS.Server/Mqtt/MqttPacketWriter.cs:8 | Added standalone UTF-8 length-prefixed `WriteString` helper |
|
||||
| mqttWriter.WriteBytes | mqtt.go:5859 | PORTED | src/NATS.Server/Mqtt/MqttPacketWriter.cs:11 | Added standalone length-prefixed `WriteBytes` helper with uint16 size guard |
|
||||
| mqttWriter.WriteVarInt | mqtt.go:5864 | PORTED | src/NATS.Server/Mqtt/MqttPacketWriter.cs:19-37 | EncodeRemainingLength implemented |
|
||||
| newMQTTWriter | mqtt.go:5878 | PARTIAL | src/NATS.Server/Mqtt/MqttPacketWriter.cs:3 | Static class, no constructor needed; Write method serves the purpose |
|
||||
|
||||
@@ -393,9 +393,9 @@ After porting work is completed:
|
||||
|
||||
| Status | Count |
|
||||
|--------|-------|
|
||||
| PORTED | 14 |
|
||||
| PORTED | 39 |
|
||||
| PARTIAL | 57 |
|
||||
| MISSING | 119 |
|
||||
| MISSING | 94 |
|
||||
| NOT_APPLICABLE | 5 |
|
||||
| DEFERRED | 0 |
|
||||
| **Total** | **195** |
|
||||
@@ -404,5 +404,7 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-25 | Ported MQTT constants/writer parity batch: internal subject/stream constants, JSA reply token constants, Sparkplug constants, MQTT→NATS header constants, plus standalone `MqttPacketWriter.WriteString/WriteBytes` helpers with targeted tests (`MqttProtocolConstantsParityBatch2Tests`). | codex |
|
||||
| 2026-02-26 | Ported MQTT helper-model parity batch: added missing helper/data models (`MqttJsa`, `MqttJsPubMsg`, `MqttRetMsgDel`, `MqttPersistedSession`, `MqttRetainedMessageRef`, `MqttSub`, `MqttFilter`, `MqttParsedPublishNatsHeader`) and extended retained message model with `Origin`/`Flags`/`Source`; verified in `MqttModelParityBatch3Tests`. | codex |
|
||||
| 2026-02-25 | Full gap analysis completed: 195 items analyzed. 14 PORTED, 57 PARTIAL, 119 MISSING, 5 NOT_APPLICABLE. Major gaps: JetStream integration (entire mqttJSA layer ~30 functions), binary protocol encoding (CONNACK/SUBACK/UNSUBACK/PUBLISH serialization), delivery callbacks (QoS0/QoS1/QoS2), account session management, retained message encoding/decoding, Sparkplug B support, NATS subject reverse mapping. .NET has solid foundation for packet reading/writing, connect parsing, basic pub/sub flow, QoS tracking, and retained store, but all are simplified/in-memory-only without JetStream backing. | claude |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
|
||||
21
gaps/plans.md
Normal file
21
gaps/plans.md
Normal file
@@ -0,0 +1,21 @@
|
||||
| Category Name | Category Gaps File Path | Design File Path | Plan File Path | Status |
|
||||
|---|---|---|---|---|
|
||||
| core-server | gaps/core-server.md | docs/plans/2026-02-25-gap-port-core-server-design.md | docs/plans/2026-02-25-gap-port-core-server-plan.md | 43 remaining |
|
||||
| protocol | gaps/protocol.md | docs/plans/2026-02-25-gap-port-protocol-design.md | docs/plans/2026-02-25-gap-port-protocol-plan.md | 9 remaining |
|
||||
| subscriptions | gaps/subscriptions.md | docs/plans/2026-02-25-gap-port-subscriptions-design.md | docs/plans/2026-02-25-gap-port-subscriptions-plan.md | complete |
|
||||
| auth-and-accounts | gaps/auth-and-accounts.md | docs/plans/2026-02-25-gap-port-auth-and-accounts-design.md | docs/plans/2026-02-25-gap-port-auth-and-accounts-plan.md | 148 remaining |
|
||||
| configuration | gaps/configuration.md | docs/plans/2026-02-25-gap-port-configuration-design.md | docs/plans/2026-02-25-gap-port-configuration-plan.md | complete |
|
||||
| routes | gaps/routes.md | docs/plans/2026-02-25-gap-port-routes-design.md | docs/plans/2026-02-25-gap-port-routes-plan.md | 36 remaining |
|
||||
| gateways | gaps/gateways.md | docs/plans/2026-02-25-gap-port-gateways-design.md | docs/plans/2026-02-25-gap-port-gateways-plan.md | 67 remaining |
|
||||
| leaf-nodes | gaps/leaf-nodes.md | docs/plans/2026-02-25-gap-port-leaf-nodes-design.md | docs/plans/2026-02-25-gap-port-leaf-nodes-plan.md | 54 remaining |
|
||||
| jetstream | gaps/jetstream.md | docs/plans/2026-02-25-gap-port-jetstream-design.md | docs/plans/2026-02-25-gap-port-jetstream-plan.md | 1084 remaining |
|
||||
| raft | gaps/raft.md | docs/plans/2026-02-25-gap-port-raft-design.md | docs/plans/2026-02-25-gap-port-raft-plan.md | 107 remaining |
|
||||
| mqtt | gaps/mqtt.md | docs/plans/2026-02-25-gap-port-mqtt-design.md | docs/plans/2026-02-25-gap-port-mqtt-plan.md | 151 remaining |
|
||||
| websocket | gaps/websocket.md | docs/plans/2026-02-25-gap-port-websocket-design.md | docs/plans/2026-02-25-gap-port-websocket-plan.md | 5 remaining |
|
||||
| monitoring | gaps/monitoring.md | docs/plans/2026-02-25-gap-port-monitoring-design.md | docs/plans/2026-02-25-gap-port-monitoring-plan.md | 96 remaining |
|
||||
| events | gaps/events.md | docs/plans/2026-02-25-gap-port-events-design.md | docs/plans/2026-02-25-gap-port-events-plan.md | 111 remaining |
|
||||
| tls-security | gaps/tls-security.md | docs/plans/2026-02-25-gap-port-tls-security-design.md | docs/plans/2026-02-25-gap-port-tls-security-plan.md | 56 remaining |
|
||||
| internal-ds | gaps/internal-ds.md | docs/plans/2026-02-25-gap-port-internal-ds-design.md | docs/plans/2026-02-25-gap-port-internal-ds-plan.md | complete |
|
||||
| logging | gaps/logging.md | docs/plans/2026-02-25-gap-port-logging-design.md | docs/plans/2026-02-25-gap-port-logging-plan.md | complete |
|
||||
| utilities-and-other | gaps/utilities-and-other.md | docs/plans/2026-02-25-gap-port-utilities-and-other-design.md | docs/plans/2026-02-25-gap-port-utilities-and-other-plan.md | 47 remaining |
|
||||
| misc-uncategorized | gaps/misc-uncategorized.md | docs/plans/2026-02-25-gap-port-misc-uncategorized-design.md | docs/plans/2026-02-25-gap-port-misc-uncategorized-plan.md | 7 remaining |
|
||||
103
gaps/protocol.md
103
gaps/protocol.md
@@ -103,8 +103,8 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `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 | MISSING | — | Helper that formats a quoted snippet of the protocol buffer for error messages. The .NET parser throws `ProtocolViolationException` with a plain message; no equivalent snippet utility exists. |
|
||||
| `client.overMaxControlLineLimit()` | parser.go:1251 | PARTIAL | `src/NATS.Server/Protocol/NatsParser.cs:82` | .NET checks `line.Length > NatsProtocol.MaxControlLineSize` and throws. Missing: kind-check (Go only enforces for `CLIENT` kind), client close on violation (`closeConnection(MaxControlLineExceeded)`), structured error with state/buffer info. |
|
||||
| `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`). |
|
||||
|
||||
@@ -114,15 +114,15 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `errProtoInsufficient` | proto.go:24 | MISSING | — | Package-level error sentinel for varint parsing. No .NET equivalent (JetStream binary encoding not yet ported). |
|
||||
| `errProtoOverflow` | proto.go:25 | MISSING | — | Package-level error sentinel. |
|
||||
| `errProtoInvalidFieldNumber` | proto.go:26 | MISSING | — | Package-level error sentinel. |
|
||||
| `protoScanField()` | proto.go:28 | MISSING | — | Scans one protobuf field (tag + value) from a byte slice. Used by JetStream internal encoding. Not yet ported. |
|
||||
| `protoScanTag()` | proto.go:42 | MISSING | — | Decodes a protobuf tag (field number + wire type) from a varint. Not yet ported. |
|
||||
| `protoScanFieldValue()` | proto.go:61 | MISSING | — | Reads the value portion of a protobuf field by wire type. Not yet ported. |
|
||||
| `protoScanVarint()` | proto.go:77 | MISSING | — | 10-byte max varint decoder. Not yet ported. |
|
||||
| `protoScanBytes()` | proto.go:179 | MISSING | — | Length-delimited bytes field reader. Not yet ported. |
|
||||
| `protoEncodeVarint()` | proto.go:190 | MISSING | — | Varint encoder. Not yet ported. |
|
||||
| `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
|
||||
|
||||
@@ -137,54 +137,54 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `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 | MISSING | — | No explicit constant in .NET; server defaults to `0.0.0.0` but the constant is not named. |
|
||||
| `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 | MISSING | — | Warning threshold for max_payload setting. No .NET equivalent. |
|
||||
| `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 | MISSING | — | Default max connections cap. No .NET equivalent constant. |
|
||||
| `TLS_TIMEOUT = 2s` | const.go:109 | MISSING | — | TLS handshake wait time. Not yet defined in .NET options. |
|
||||
| `DEFAULT_TLS_HANDSHAKE_FIRST_FALLBACK_DELAY = 50ms` | const.go:114 | MISSING | — | TLS-first handshake fallback delay. Not yet implemented in .NET. |
|
||||
| `AUTH_TIMEOUT = 2s` | const.go:118 | MISSING | — | Authorization wait timeout. No .NET equivalent constant. |
|
||||
| `DEFAULT_PING_INTERVAL = 2min` | const.go:122 | MISSING | — | Ping interval for keep-alive. No .NET equivalent. |
|
||||
| `DEFAULT_PING_MAX_OUT = 2` | const.go:125 | MISSING | — | Max outstanding pings before disconnect. No .NET equivalent. |
|
||||
| `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 | MISSING | — | Write/flush deadline. Not yet defined. |
|
||||
| `DEFAULT_HTTP_PORT = 8222` | const.go:137 | MISSING | — | Monitoring port. Not yet implemented. |
|
||||
| `DEFAULT_HTTP_BASE_PATH = "/"` | const.go:140 | MISSING | — | Monitoring HTTP base path. Not yet implemented. |
|
||||
| `ACCEPT_MIN_SLEEP = 10ms` | const.go:143 | MISSING | — | Retry sleep for transient accept errors. Not yet defined. |
|
||||
| `ACCEPT_MAX_SLEEP = 1s` | const.go:146 | MISSING | — | Max sleep for accept errors. Not yet defined. |
|
||||
| `DEFAULT_ROUTE_CONNECT = 1s` | const.go:149 | MISSING | — | Route solicitation interval. Clustering not yet implemented. |
|
||||
| `DEFAULT_ROUTE_CONNECT_MAX = 30s` | const.go:152 | MISSING | — | Route max solicitation interval. |
|
||||
| `DEFAULT_ROUTE_RECONNECT = 1s` | const.go:155 | MISSING | — | Route reconnect delay. |
|
||||
| `DEFAULT_ROUTE_DIAL = 1s` | const.go:158 | MISSING | — | Route dial timeout. |
|
||||
| `DEFAULT_ROUTE_POOL_SIZE = 3` | const.go:161 | MISSING | — | Route connection pool size. |
|
||||
| `DEFAULT_LEAF_NODE_RECONNECT = 1s` | const.go:164 | MISSING | — | Leaf node reconnect interval. |
|
||||
| `DEFAULT_LEAF_TLS_TIMEOUT = 2s` | const.go:167 | MISSING | — | Leaf node TLS timeout. |
|
||||
| `PROTO_SNIPPET_SIZE = 32` | const.go:170 | MISSING | — | Size of proto snippet in parse errors. No .NET equivalent (errors use plain messages). |
|
||||
| `MAX_CONTROL_LINE_SNIPPET_SIZE = 128` | const.go:172 | MISSING | — | Snippet size for control-line-too-long errors. |
|
||||
| `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 | MISSING | — | Closed-connection history cap. Not yet implemented. |
|
||||
| `DEFAULT_LAME_DUCK_DURATION = 2min` | const.go:196 | MISSING | — | Lame-duck shutdown spread duration. Not yet implemented. |
|
||||
| `DEFAULT_LAME_DUCK_GRACE_PERIOD = 10s` | const.go:200 | MISSING | — | Lame-duck grace period. Not yet implemented. |
|
||||
| `DEFAULT_LEAFNODE_INFO_WAIT = 1s` | const.go:203 | MISSING | — | Leaf node INFO wait. Not yet implemented. |
|
||||
| `DEFAULT_LEAFNODE_PORT = 7422` | const.go:206 | MISSING | — | Default leaf node port. Not yet implemented. |
|
||||
| `DEFAULT_CONNECT_ERROR_REPORTS = 3600` | const.go:214 | MISSING | — | Error report throttle for initial connection failures. Not yet implemented. |
|
||||
| `DEFAULT_RECONNECT_ERROR_REPORTS = 1` | const.go:220 | MISSING | — | Error report throttle for reconnect failures. Not yet implemented. |
|
||||
| `DEFAULT_RTT_MEASUREMENT_INTERVAL = 1h` | const.go:224 | MISSING | — | RTT measurement interval. Not yet implemented. |
|
||||
| `DEFAULT_ALLOW_RESPONSE_MAX_MSGS = 1` | const.go:228 | MISSING | — | Default allowed response message count for reply subjects. Not yet implemented. |
|
||||
| `DEFAULT_ALLOW_RESPONSE_EXPIRATION = 2min` | const.go:232 | MISSING | — | Dynamic response permission expiry. Not yet implemented. |
|
||||
| `DEFAULT_SERVICE_EXPORT_RESPONSE_THRESHOLD = 2min` | const.go:237 | MISSING | — | Service export response threshold. Not yet implemented (accounts/JetStream). |
|
||||
| `DEFAULT_SERVICE_LATENCY_SAMPLING = 100` | const.go:241 | MISSING | — | Service latency sampling rate. Not yet implemented. |
|
||||
| `DEFAULT_SYSTEM_ACCOUNT = "$SYS"` | const.go:244 | MISSING | — | System account name constant. Not yet implemented. |
|
||||
| `DEFAULT_GLOBAL_ACCOUNT = "$G"` | const.go:247 | MISSING | — | Global account name constant. Not yet implemented. |
|
||||
| `DEFAULT_ACCOUNT_FETCH_TIMEOUT = 1900ms` | const.go:250 | MISSING | — | Account fetch timeout. Not yet implemented. |
|
||||
| `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)
|
||||
|
||||
@@ -231,7 +231,7 @@ After porting work is completed:
|
||||
| `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` | MISSING | No .NET test for integer overflow on very large size values (>9 digits handled by `ParseSize` returning -1, but no explicit overflow test) |
|
||||
| `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` |
|
||||
@@ -240,7 +240,7 @@ After porting work is completed:
|
||||
| `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` | MISSING | No .NET equivalent for `protoSnippet()` helper |
|
||||
| `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) |
|
||||
|
||||
@@ -281,5 +281,8 @@ After porting work is completed:
|
||||
|
||||
| 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 |
|
||||
|
||||
62
gaps/raft.md
62
gaps/raft.md
@@ -91,12 +91,12 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| 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 | PARTIAL | src/NATS.Server/Raft/RaftPeerState.cs:7 | .NET has NextIndex/MatchIndex/LastContact/Active but missing Lag and Current fields from Go's Peer export |
|
||||
| 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 | MISSING | — | No .NET ToString override for RaftState enum |
|
||||
| RaftConfig (struct) | raft.go:301-317 | MISSING | — | No equivalent configuration struct (Name, Store, Log, Track, Observer, Recovering, ScaleUp) |
|
||||
| CommittedEntry (struct) | raft.go:2506-2509 | PARTIAL | src/NATS.Server/Raft/CommitQueue.cs:9 | CommitQueue<T> exists as channel wrapper, but no CommittedEntry struct with Index+Entries |
|
||||
| Entry (struct) | raft.go:2641-2644 | PARTIAL | src/NATS.Server/Raft/RaftWireFormat.cs:73 | RaftEntryWire has Type+Data but is wire-format only; no general Entry type used for proposals |
|
||||
| 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
|
||||
@@ -104,53 +104,53 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| 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 | MISSING | — | No batch proposal support |
|
||||
| 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 | MISSING | — | No callback from upper layer for applied index tracking (delegates to Processed) |
|
||||
| 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 | MISSING | — | No WAL size reporting |
|
||||
| Progress() | raft.go:2030-2034 | MISSING | — | No combined (index, commit, applied) return |
|
||||
| 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 | MISSING | — | No leader-since timestamp tracking |
|
||||
| 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 | MISSING | — | No atomic hasleader flag |
|
||||
| GroupLeader() | raft.go:1865-1872 | MISSING | — | No leader ID tracking (only IsLeader bool) |
|
||||
| HadPreviousLeader() | raft.go:1860-1862 | MISSING | — | No pleader atomic flag |
|
||||
| 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 | MISSING | — | No observer mode |
|
||||
| IsObserver() | raft.go:2387-2391 | MISSING | — | No observer mode |
|
||||
| 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 | MISSING | — | No group name tracking |
|
||||
| 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 | MISSING | — | No cluster size adjustment |
|
||||
| AdjustBootClusterSize() | raft.go:1038-1055 | MISSING | — | No boot cluster size adjustment |
|
||||
| ClusterSize() | raft.go:1029-1033 | MISSING | — | No explicit cluster size 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 | MISSING | — | No creation timestamp |
|
||||
| Stop() | raft.go:2120-2122 | MISSING | — | No graceful shutdown (Dispose exists but minimal) |
|
||||
| WaitForStop() | raft.go:2124-2128 | MISSING | — | No wait-for-stop mechanism |
|
||||
| Delete() | raft.go:2130-2143 | MISSING | — | No delete with WAL cleanup |
|
||||
| IsDeleted() | raft.go:2145-2149 | MISSING | — | No deleted flag |
|
||||
| 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 |
|
||||
@@ -224,7 +224,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| 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 | MISSING | — | No separate campaign timeout |
|
||||
| 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
|
||||
|
||||
@@ -350,12 +350,12 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| 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 | MISSING | — | No heartbeat interval constant |
|
||||
| lostQuorumInterval | raft.go:284 | MISSING | — | No lost quorum interval |
|
||||
| observerModeInterval | raft.go:286 | MISSING | — | No observer mode interval |
|
||||
| peerRemoveTimeout | raft.go:287 | MISSING | — | No peer remove timeout |
|
||||
| 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 | MISSING | — | No explicit no-leader/no-vote constants |
|
||||
| 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 |
|
||||
@@ -387,3 +387,5 @@ After porting work is completed:
|
||||
|------|--------|----|
|
||||
| 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 |
|
||||
|
||||
@@ -92,12 +92,12 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `RouteType` (type alias + consts `Implicit`/`Explicit`) | route.go:36–44 | PORTED | `src/NATS.Server/Routes/RouteConnection.cs` — implicit/explicit distinction tracked in `RouteConnection` handshake and `RouteManager.ConnectToRouteWithRetryAsync` | No explicit enum; Implicit/Explicit distinction is encoded in how routes are established (solicited vs inbound) |
|
||||
| `route` struct (unexported) | route.go:56–94 | PARTIAL | `src/NATS.Server/Routes/RouteConnection.cs:8` | Fields `remoteID`, `poolIdx`, `accName`, `noPool`, `compression`, `gossipMode` are present. Fields for `lnoc`, `lnocu`, `jetstream`, `connectURLs`, `wsConnURLs`, `gatewayURL`, `leafnodeURL`, `hash`, `idHash`, `startNewRoute`, `retry` are MISSING — not modelled in .NET |
|
||||
| `routeInfo` struct (unexported) | route.go:97–101 | MISSING | — | Used internally for deferred pool-connection creation after first PONG; no .NET equivalent |
|
||||
| `gossipDefault`/`gossipDisabled`/`gossipOverride` consts | route.go:104–108 | MISSING | — | Gossip mode bytes used in INFO propagation; not implemented in .NET |
|
||||
| `connectInfo` struct | route.go:110–124 | PARTIAL | `src/NATS.Server/Routes/RouteConnection.cs:328` (`BuildConnectInfoJson`) | .NET builds a simplified JSON payload; `connectInfo` fields Echo, Verbose, Pedantic, TLS, Headers, Cluster, Dynamic, LNOC, LNOCU are all MISSING from the .NET payload |
|
||||
| `ConProto`/`InfoProto` protocol format strings | route.go:127–130 | PARTIAL | `src/NATS.Server/Routes/RouteConnection.cs:73,83` | Handshake uses a simplified `ROUTE <serverId>` format rather than `CONNECT <json>` / `INFO <json>` |
|
||||
| `gossipDefault`/`gossipDisabled`/`gossipOverride` consts | route.go:104–108 | PORTED | `src/NATS.Server/Routes/RouteManager.cs:17–19` | Gossip mode constants are defined as byte constants (`GossipDefault`, `GossipDisabled`, `GossipOverride`) |
|
||||
| `connectInfo` struct | route.go:110–124 | PORTED | `src/NATS.Server/Routes/RouteConnection.cs:378` (`BuildConnectInfoJson`) | Connect payload now includes parity fields: `echo`, `verbose`, `pedantic`, `tls_required`, `headers`, `cluster`, `dynamic`, `lnoc`, `lnocu` |
|
||||
| `ConProto`/`InfoProto` protocol format strings | route.go:127–130 | PARTIAL | `src/NATS.Server/Routes/RouteConnection.cs:11–12,83–95` | CONNECT/INFO format constants added, but active wire handshake remains simplified `ROUTE <serverId>` rather than full CONNECT/INFO exchange |
|
||||
| `clusterTLSInsecureWarning` const | route.go:134 | NOT_APPLICABLE | — | TLS not yet implemented in .NET port; warning string has no counterpart |
|
||||
| `defaultRouteMaxPingInterval` const | route.go:140 | MISSING | — | Ping interval management for compression RTT auto-mode not implemented |
|
||||
| `routeConnectDelay`/`routeConnectMaxDelay`/`routeMaxPingInterval` vars | route.go:145–148 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:486` (250ms hardcoded delay) | .NET hardcodes 250ms retry delay; Go uses configurable `DEFAULT_ROUTE_CONNECT` with exponential backoff |
|
||||
| `defaultRouteMaxPingInterval` const | route.go:140 | PORTED | `src/NATS.Server/Routes/RouteManager.cs:20` | `DefaultRouteMaxPingInterval` constant added |
|
||||
| `routeConnectDelay`/`routeConnectMaxDelay`/`routeMaxPingInterval` vars | route.go:145–148 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:14–15,20,751–757` | Route reconnect delay now uses bounded exponential backoff (`ComputeRetryDelay`) with dedicated delay/max constants; still not runtime-configurable from route config |
|
||||
| `(c *client) removeReplySub` | route.go:151 | MISSING | — | Reply-sub cleanup for remote reply subs not implemented |
|
||||
| `(c *client) processAccountSub` | route.go:167 | NOT_APPLICABLE | — | Gateway-only path; gateway sub interest not in routes module |
|
||||
| `(c *client) processAccountUnsub` | route.go:174 | NOT_APPLICABLE | — | Gateway-only path |
|
||||
@@ -110,48 +110,48 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `(c *client) processRouteInfo` | route.go:549 | MISSING | — | Full INFO processing (cluster name negotiation, compression negotiation, duplicate detection, account route setup) not implemented; .NET handshake is a simple ID exchange |
|
||||
| `(s *Server) negotiateRouteCompression` | route.go:897 | PARTIAL | `src/NATS.Server/Routes/RouteCompressionCodec.cs:82` (`NegotiateCompression`) | .NET has the negotiation logic; but integration into handshake (INFO exchange, switching compression writer/reader mid-stream) is MISSING |
|
||||
| `(s *Server) updateRemoteRoutePerms` | route.go:953 | MISSING | — | Route permission update on INFO reload not implemented |
|
||||
| `(s *Server) sendAsyncInfoToClients` | route.go:1015 | MISSING | — | Async INFO broadcast to connected clients not implemented |
|
||||
| `(s *Server) processImplicitRoute` | route.go:1043 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:107` (`ProcessImplicitRoute`) | .NET collects discovered URLs; missing: duplicate-ID check, pinned-account re-solicitation, `hasThisRouteConfigured` guard |
|
||||
| `(s *Server) hasThisRouteConfigured` | route.go:1104 | MISSING | — | Check whether incoming gossip URL is already a configured explicit route; not implemented |
|
||||
| `(s *Server) sendAsyncInfoToClients` | route.go:1015 | PORTED | `src/NATS.Server/NatsServer.cs:181` | Added `UpdateServerINFOAndSendINFOToClients()` INFO refresh/broadcast path to connected clients; validated with targeted socket-level parity test. |
|
||||
| `(s *Server) processImplicitRoute` | route.go:1043 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:115` (`ProcessImplicitRoute`) | Now guards discovered URLs with `HasThisRouteConfigured` and normalized duplicate checks; pinned-account re-solicitation and duplicate-ID handling remain missing |
|
||||
| `(s *Server) hasThisRouteConfigured` | route.go:1104 | PORTED | `src/NATS.Server/Routes/RouteManager.cs:164` | Implemented with normalized URL matching against explicit configured routes and known route URLs |
|
||||
| `(s *Server) forwardNewRouteInfoToKnownServers` | route.go:1139 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:127` (`ForwardNewRouteInfoToKnownServers`) | .NET raises an event with the new peer URL; missing: gossip mode logic (`gossipDefault`/`gossipDisabled`/`gossipOverride`), pinned-account route filtering, serialized INFO JSON sending |
|
||||
| `(c *client) canImport` | route.go:1226 | MISSING | — | Route import permission check not implemented |
|
||||
| `(c *client) canExport` | route.go:1235 | MISSING | — | Route export permission check not implemented |
|
||||
| `(c *client) setRoutePermissions` | route.go:1244 | MISSING | — | Route permission mapping (Import→Publish, Export→Subscribe) not implemented |
|
||||
| `asubs` struct | route.go:1263 | NOT_APPLICABLE | — | Internal Go helper to group subscriptions by account during cleanup; .NET uses LINQ equivalents |
|
||||
| `getAccNameFromRoutedSubKey` | route.go:1273 | MISSING | — | Sub key parsing for account name extraction not implemented |
|
||||
| `(c *client) getRoutedSubKeyInfo` | route.go:1290 | MISSING | — | Helper to determine account/key info for a route's subscriptions; not implemented |
|
||||
| `(c *client) removeRemoteSubs` | route.go:1299 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:577` (`RemoveRoute`) | .NET removes the route connection but does NOT remove individual remote subscriptions from the SubList on close |
|
||||
| `(c *client) removeRemoteSubsForAcc` | route.go:1352 | MISSING | — | Per-account remote sub removal for dedicated route transition not implemented |
|
||||
| `(c *client) parseUnsubProto` | route.go:1366 | MISSING | — | RS-/LS- protocol arg parser not implemented; .NET `ReadFramesAsync` only extracts account/subject/queue loosely |
|
||||
| `getAccNameFromRoutedSubKey` | route.go:1273 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:176` (`GetAccNameFromRoutedSubKey`) | Routed-sub key parsing helper added and validated with parity tests |
|
||||
| `(c *client) getRoutedSubKeyInfo` | route.go:1290 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:179` (`GetRoutedSubKeyInfo`) | Routed-sub key decomposition helper added (route/account/subject/queue) and covered by tests |
|
||||
| `(c *client) removeRemoteSubs` | route.go:1299 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:195` (`RemoveRemoteSubs`), `src/NATS.Server/Routes/RouteManager.cs:593` (`WatchRouteAsync`), `src/NATS.Server/NatsServer.cs:960` (`RemoveRemoteSubscriptionsForRoute`) | Route close/removal now triggers remote-sub cleanup from account SubLists when the last connection for a remote server is gone |
|
||||
| `(c *client) removeRemoteSubsForAcc` | route.go:1352 | PARTIAL | `src/NATS.Server/Subscriptions/SubList.cs:229` (`RemoveRemoteSubsForAccount`), `src/NATS.Server/Routes/RouteManager.cs:286` (`UnregisterAccountRoute`), `src/NATS.Server/NatsServer.cs:966` (`RemoveRemoteSubscriptionsForRouteAccount`) | Per-account cleanup path is now wired on dedicated-route unregistration; full dedicated-route transition parity remains incomplete |
|
||||
| `(c *client) parseUnsubProto` | route.go:1366 | PORTED | `src/NATS.Server/Routes/RouteConnection.cs:357` (`TryParseRemoteUnsub`) | Dedicated RS-/LS- parser now handles account/subject/optional-queue extraction and is used by frame processing |
|
||||
| `(c *client) processRemoteUnsub` | route.go:1404 | PARTIAL | `src/NATS.Server/Routes/RouteConnection.cs:177–185` | .NET fires `RemoteSubscriptionReceived` with `IsRemoval=true`; missing: sub key lookup and removal from SubList, gateway/leafnode interest updates |
|
||||
| `(c *client) processRemoteSub` | route.go:1489 | PARTIAL | `src/NATS.Server/Routes/RouteConnection.cs:167–175` | .NET fires `RemoteSubscriptionReceived`; missing: key construction with type byte prefix, account lookup/creation, permission check (`canExport`), SubList insertion, gateway/leafnode updates, queue-weight delta tracking |
|
||||
| `(c *client) addRouteSubOrUnsubProtoToBuf` | route.go:1729 | PARTIAL | `src/NATS.Server/Routes/RouteConnection.cs:95–109` (`SendRsPlusAsync`/`SendRsMinusAsync`) | .NET sends RS+/RS- with account and optional queue; missing: LS+/LS- variant for leaf origin clusters, queue weight field in RS+ |
|
||||
| `(c *client) addRouteSubOrUnsubProtoToBuf` | route.go:1729 | PORTED | `src/NATS.Server/Routes/RouteConnection.cs:179` (`SendRouteSubOrUnSubProtosAsync`) | Added low-level buffered route-proto sender that batches RS+/RS-/LS+/LS- control lines into a single write/flush. |
|
||||
| `(s *Server) sendSubsToRoute` | route.go:1781 | MISSING | — | Bulk send of local subscription interest to newly connected route not implemented; .NET only propagates incremental sub/unsub |
|
||||
| `(c *client) sendRouteSubProtos` | route.go:1881 | MISSING | — | Batch RS+ send not implemented |
|
||||
| `(c *client) sendRouteUnSubProtos` | route.go:1890 | MISSING | — | Batch RS- send not implemented |
|
||||
| `(c *client) sendRouteSubOrUnSubProtos` | route.go:1898 | MISSING | — | Low-level batch RS+/RS-/LS+/LS- sender not implemented |
|
||||
| `(c *client) sendRouteSubProtos` | route.go:1881 | PORTED | `src/NATS.Server/Routes/RouteConnection.cs:146` (`SendRouteSubProtosAsync`) | Added batched RS+ emission from remote-subscription models with queue/weight support. |
|
||||
| `(c *client) sendRouteUnSubProtos` | route.go:1890 | PORTED | `src/NATS.Server/Routes/RouteConnection.cs:165` (`SendRouteUnSubProtosAsync`) | Added batched RS- emission from remote-subscription models. |
|
||||
| `(c *client) sendRouteSubOrUnSubProtos` | route.go:1898 | PORTED | `src/NATS.Server/Routes/RouteConnection.cs:179` (`SendRouteSubOrUnSubProtosAsync`) | Added low-level batch sender for arbitrary route sub/unsub protocol lines. |
|
||||
| `(s *Server) createRoute` | route.go:1935 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:447,462` (`HandleInboundRouteAsync`/`ConnectToRouteWithRetryAsync`) | .NET creates a RouteConnection and performs handshake; missing: TLS setup, auth timeout timer, CONNECT protocol sending, INFO JSON sending, compression negotiation, ping timer |
|
||||
| `routeShouldDelayInfo` | route.go:2082 | MISSING | — | Logic to delay initial INFO until pool connection auth is confirmed not implemented |
|
||||
| `(s *Server) generateRouteInitialInfoJSON` | route.go:2090 | MISSING | — | Route INFO JSON generation (with nonce, pool index, gossip mode, compression) not implemented |
|
||||
| `(s *Server) addRoute` | route.go:2113 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:496` (`Register`) | .NET registers route in dictionary; missing: pool index management, duplicate detection with `handleDuplicateRoute`, per-account route registration in `accRoutes`, `sendSubsToRoute` call, gateway/leafnode URL propagation, `forwardNewRouteInfoToKnownServers` |
|
||||
| `hasSolicitedRoute` | route.go:2438 | MISSING | — | Helper to find a solicited route in a pool slice; not implemented |
|
||||
| `upgradeRouteToSolicited` | route.go:2458 | MISSING | — | Upgrade an inbound route to solicited status; not implemented |
|
||||
| `hasSolicitedRoute` | route.go:2438 | PORTED | `src/NATS.Server/Routes/RouteManager.cs:721` | Implemented helper to query whether a given remote server currently has a solicited route |
|
||||
| `upgradeRouteToSolicited` | route.go:2458 | PORTED | `src/NATS.Server/Routes/RouteManager.cs:730` | Implemented route upgrade helper to flip an existing route into solicited mode |
|
||||
| `handleDuplicateRoute` | route.go:2473 | MISSING | — | Duplicate route resolution (close extra connection, preserve retry flag) not implemented |
|
||||
| `(c *client) importFilter` | route.go:2510 | MISSING | — | Permission-based subscription filter for sending to routes not implemented |
|
||||
| `(s *Server) updateRouteSubscriptionMap` | route.go:2519 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:381,392` (`PropagateLocalSubscription`/`PropagateLocalUnsubscription`) | .NET broadcasts RS+/RS- to all routes; missing: account routePoolIdx-based routing, queue-weight dedup (`sqmu`/`lqws`), no-pool route handling, gateway/leafnode interest updates |
|
||||
| `(s *Server) startRouteAcceptLoop` | route.go:2696 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:333` (`StartAsync`) | .NET binds and starts accept loop, solicits configured routes; missing: cluster name logging, TLS config on accept, routeInfo construction, advertise/NoAdvertise, LeafNode/Gateway URL propagation |
|
||||
| `(s *Server) setRouteInfoHostPortAndIP` | route.go:2829 | MISSING | — | Route INFO host/port/IP with Cluster.Advertise support not implemented |
|
||||
| `(s *Server) StartRouting` | route.go:2849 | PORTED | `src/NATS.Server/Routes/RouteManager.cs:333` (`StartAsync`) | Functionally equivalent: starts accept loop and solicits routes |
|
||||
| `(s *Server) reConnectToRoute` | route.go:2861 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:462` (`ConnectToRouteWithRetryAsync`) | .NET retries indefinitely with 250ms delay; missing: random jitter delay, explicit vs implicit distinction affecting delay, quit-channel integration |
|
||||
| `(s *Server) routeStillValid` | route.go:2881 | MISSING | — | Check that a route URL is still in configured routes list (for reconnect guard) not implemented |
|
||||
| `(s *Server) connectToRoute` | route.go:2890 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:462` (`ConnectToRouteWithRetryAsync`) | .NET connects and retries; missing: explicit/implicit distinction, ConnectRetries limit, exponential backoff (`ConnectBackoff`), `routesToSelf` exclusion, address randomization from DNS |
|
||||
| `(c *client) isSolicitedRoute` | route.go:2976 | MISSING | — | Helper predicate; not implemented |
|
||||
| `(s *Server) reConnectToRoute` | route.go:2861 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:512` (`ConnectToRouteWithRetryAsync`) | Retry loop now uses bounded exponential backoff and route validity guard; jitter, explicit/implicit-specific delay behavior, and quit-channel parity remain missing |
|
||||
| `(s *Server) routeStillValid` | route.go:2881 | PORTED | `src/NATS.Server/Routes/RouteManager.cs:180` | Implemented reconnect guard that validates configured and discovered route URLs using normalized comparisons |
|
||||
| `(s *Server) connectToRoute` | route.go:2890 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:512` (`ConnectToRouteWithRetryAsync`) | Exponential backoff and route-validity checks are implemented; ConnectRetries/ConnectBackoff config parity, routes-to-self exclusion, and DNS randomization are still missing |
|
||||
| `(c *client) isSolicitedRoute` | route.go:2976 | PORTED | `src/NATS.Server/Routes/RouteConnection.cs:35,370` | `IsSolicited` state is tracked on route connections and exposed via `IsSolicitedRoute()` helper |
|
||||
| `(s *Server) saveRouteTLSName` | route.go:2985 | NOT_APPLICABLE | — | TLS not yet implemented in .NET port |
|
||||
| `(s *Server) solicitRoutes` | route.go:2996 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:347–354` | .NET solicits configured routes with pool connections; missing: per-account (pinned) route solicitation, `saveRouteTLSName` |
|
||||
| `(c *client) processRouteConnect` | route.go:3011 | MISSING | — | Parsing and validation of inbound CONNECT from route (cluster name check, wrong-port detection, LNOC/LNOCU flags) not implemented; .NET uses a simpler handshake |
|
||||
| `(s *Server) removeAllRoutesExcept` | route.go:3085 | PORTED | `src/NATS.Server/Routes/RouteManager.cs:602` (`RemoveAllRoutesExcept`) | Equivalent behavior: remove all routes not in the keep-set |
|
||||
| `(s *Server) removeRoute` | route.go:3113 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:577` (`RemoveRoute`) | .NET removes from `_routes` dict; missing: per-account route cleanup (`accRoutes`), hash removal, gateway/leafnode URL withdrawal, noPool counter, reconnect-after-noPool logic |
|
||||
| `(s *Server) isDuplicateServerName` | route.go:3233 | MISSING | — | Duplicate server name detection across routes not implemented |
|
||||
| `(s *Server) removeRoute` | route.go:3113 | PARTIAL | `src/NATS.Server/Routes/RouteManager.cs:632` (`RemoveRoute`) | Remove path now also cleans hash index and per-account route mappings tied to removed connections; gateway/leafnode URL withdrawal, noPool counters, and reconnect-after-noPool logic remain missing |
|
||||
| `(s *Server) isDuplicateServerName` | route.go:3233 | PORTED | `src/NATS.Server/Routes/RouteManager.cs:748` | Duplicate server-name detection helper implemented against current connected-server ID set |
|
||||
| `(s *Server) forEachNonPerAccountRoute` | route.go:3263 | NOT_APPLICABLE | — | Internal Go iterator over route slice; .NET uses `_routes.Values` LINQ directly |
|
||||
| `(s *Server) forEachRoute` | route.go:3277 | NOT_APPLICABLE | — | Internal Go iterator; .NET enumerates `_routes` and `_accountRoutes` directly |
|
||||
| `(s *Server) forEachRouteIdx` | route.go:3292 | NOT_APPLICABLE | — | Internal Go pool-index iterator; .NET `ComputeRoutePoolIdx` achieves equivalent selection |
|
||||
@@ -182,5 +182,9 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Ported async INFO broadcast parity slice: wired/validated `UpdateServerINFOAndSendINFOToClients()` as the `sendAsyncInfoToClients` equivalent and added targeted socket broadcast test (`RouteInfoBroadcastParityBatch4Tests`). | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Full gap inventory populated: 57 Go symbols classified across route.go (3,314 lines). Counts: PORTED 4, PARTIAL 21, MISSING 23, NOT_APPLICABLE 9, DEFERRED 0 | auto |
|
||||
| 2026-02-25 | Ported route parity helper batch: gossip/default constants, connect-info parity fields, configured-route/reconnect guard helpers, solicited-route helpers, duplicate-server-name detection, RS-/LS- parser, and LS+/LS- + queue-weight wire helpers; updated row statuses and notes | codex |
|
||||
| 2026-02-25 | Ported routed-sub key helpers and remote-sub cleanup parity batch: added `getAccNameFromRoutedSubKey`/`getRoutedSubKeyInfo` equivalents plus route-close and per-account cleanup plumbing with targeted tests | codex |
|
||||
| 2026-02-25 | Ported route batch-proto parity batch: added buffered batch sender APIs (`SendRouteSubProtosAsync`, `SendRouteUnSubProtosAsync`, `SendRouteSubOrUnSubProtosAsync`) for RS+/RS-/LS+/LS- protocol frames with targeted tests (`RouteBatchProtoParityBatch3Tests`) | codex |
|
||||
|
||||
@@ -100,14 +100,14 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `level` (struct) | sublist.go:96 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:967` (private `TrieLevel`) | Inner class; `nodes`, `pwc`, `fwc` all present |
|
||||
| `newNode()` | sublist.go:102 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:974` | Inline `new TrieNode()` |
|
||||
| `newLevel()` | sublist.go:107 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:967` | Inline `new TrieLevel()` |
|
||||
| `NewSublist(bool)` | sublist.go:117 | PARTIAL | `src/NATS.Server/Subscriptions/SubList.cs:11` | .NET `SubList` always starts with cache; no `enableCache` constructor param |
|
||||
| `NewSublist(bool)` | sublist.go:117 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:40` | Added `SubList(bool enableCache)` constructor to explicitly control cache behavior |
|
||||
| `NewSublistWithCache()` | sublist.go:125 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:11` | Default `new SubList()` has cache enabled |
|
||||
| `NewSublistNoCache()` | sublist.go:130 | MISSING | — | No .NET equivalent; SubList always caches |
|
||||
| `CacheEnabled()` | sublist.go:135 | MISSING | — | No public method to query whether cache is on; `CacheCount` exists but different semantics |
|
||||
| `RegisterNotification()` | sublist.go:149 | MISSING | — | Go sends `true/false` on channel when first/last interest added/removed; .NET uses `InterestChanged` event which fires on every change but doesn't replicate channel-based deferred notify semantics |
|
||||
| `RegisterQueueNotification()` | sublist.go:153 | MISSING | — | Queue-specific interest notification; no .NET equivalent |
|
||||
| `ClearNotification()` | sublist.go:227 | MISSING | — | No .NET equivalent for removing a notification channel |
|
||||
| `ClearQueueNotification()` | sublist.go:231 | MISSING | — | No .NET equivalent |
|
||||
| `NewSublistNoCache()` | sublist.go:130 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:46` | Added `NewSublistNoCache()` factory returning `new SubList(false)` |
|
||||
| `CacheEnabled()` | sublist.go:135 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:48` | Added `CacheEnabled()` to expose current cache mode |
|
||||
| `RegisterNotification()` | sublist.go:149 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:50` | Added first/last-interest callback registration (`Action<bool>`) and transition notifications in `Insert`/`Remove` |
|
||||
| `RegisterQueueNotification()` | sublist.go:153 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:57` | Added queue-scoped first/last-interest callback registration with immediate current-state callback and insert/remove transition tracking |
|
||||
| `ClearNotification()` | sublist.go:227 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:52` | Added notification callback clearing method |
|
||||
| `ClearQueueNotification()` | sublist.go:231 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:83` | Added queue-scoped notification de-registration across both insert/remove transition maps |
|
||||
| `chkForInsertNotification()` | sublist.go:301 | NOT_APPLICABLE | — | Internal helper for channel notification; replaced by `InterestChanged` event emission in `Insert()` |
|
||||
| `chkForRemoveNotification()` | sublist.go:317 | NOT_APPLICABLE | — | Internal helper; replaced by `InterestChanged` event emission in `Remove()` |
|
||||
| `sendNotification()` | sublist.go:253 | NOT_APPLICABLE | — | Non-blocking channel send; Go-specific pattern, no .NET equivalent needed |
|
||||
@@ -129,7 +129,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `hasInterest()` | sublist.go:624 | NOT_APPLICABLE | — | Internal; maps to `HasInterestLevel()` private helper |
|
||||
| `reduceCacheCount()` | sublist.go:675 | PORTED | `src/NATS.Server/Subscriptions/SubListCacheSweeper.cs:7` + `SubList.cs:458` | Background goroutine mapped to `SubListCacheSweeper` + `SweepCache()` |
|
||||
| `isRemoteQSub()` | sublist.go:689 | NOT_APPLICABLE | — | Go has client.kind == ROUTER/LEAF; .NET uses `RemoteSubscription` model instead |
|
||||
| `UpdateRemoteQSub()` | sublist.go:695 | MISSING | — | Go updates weight of remote qsub; .NET uses `ApplyRemoteSub()` for a different model (full add/remove) |
|
||||
| `UpdateRemoteQSub()` | sublist.go:695 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:218` | Added remote queue-sub weight update path that mutates existing entry and bumps generation |
|
||||
| `addNodeToResults()` | sublist.go:706 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:549` (private `AddNodeToResults()`) | Remote qsub weight expansion present in Go missing in .NET |
|
||||
| `findQSlot()` | sublist.go:745 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:562` (inline in `AddNodeToResults`) | Inlined in .NET |
|
||||
| `matchLevel()` | sublist.go:757 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:506` (private `MatchLevel()`) | Core trie descent algorithm |
|
||||
@@ -144,33 +144,33 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `Count()` | sublist.go:1023 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:41` (`Count` property) | |
|
||||
| `CacheCount()` | sublist.go:1030 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:97` (`CacheCount` property) | |
|
||||
| `SublistStats` (struct) | sublist.go:1038 | PORTED | `src/NATS.Server/Subscriptions/SubListStats.cs:3` | All public fields present; unexported fields `totFanout`, `cacheCnt`, `cacheHits` dropped (computed inline in `Stats()`) |
|
||||
| `SublistStats.add()` | sublist.go:1052 | MISSING | — | Aggregates multiple SublistStats into one; used for cluster monitoring; no .NET equivalent |
|
||||
| `SublistStats.add()` | sublist.go:1052 | PORTED | `src/NATS.Server/Subscriptions/SubListStats.cs:18` | Added `Add(SubListStats)` aggregation including cache-hit, fanout, and max-fanout rollups |
|
||||
| `Stats()` | sublist.go:1076 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:580` | Full fanout stats computed |
|
||||
| `numLevels()` | sublist.go:1120 | MISSING | — | Debug/test utility counting trie depth; not ported |
|
||||
| `visitLevel()` | sublist.go:1126 | MISSING | — | Internal helper for `numLevels()`; not ported |
|
||||
| `subjectHasWildcard()` | sublist.go:1159 | PARTIAL | `src/NATS.Server/Subscriptions/SubjectMatch.cs:50` (`IsLiteral()` — inverse) | .NET `!IsLiteral()` is equivalent but not a dedicated function |
|
||||
| `numLevels()` | sublist.go:1120 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:1030` | Added internal trie-depth utility (`NumLevels`) for parity/debug verification |
|
||||
| `visitLevel()` | sublist.go:1126 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:1223` | Added recursive depth traversal helper used by `NumLevels()` |
|
||||
| `subjectHasWildcard()` | sublist.go:1159 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:72` | Added dedicated `SubjectHasWildcard()` helper |
|
||||
| `subjectIsLiteral()` | sublist.go:1174 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:50` (`IsLiteral()`) | Exact equivalent |
|
||||
| `IsValidPublishSubject()` | sublist.go:1187 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:67` | |
|
||||
| `IsValidSubject()` | sublist.go:1192 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:9` | |
|
||||
| `isValidSubject()` (internal, checkRunes) | sublist.go:1196 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:211` (`IsValidSubject(string, bool)`) | |
|
||||
| `IsValidLiteralSubject()` | sublist.go:1236 | PARTIAL | `src/NATS.Server/Subscriptions/SubjectMatch.cs:50` (`IsLiteral()`) | `IsLiteral()` does not validate the subject first; `IsValidPublishSubject()` combines both |
|
||||
| `IsValidLiteralSubject()` | sublist.go:1236 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:74` | Added dedicated `IsValidLiteralSubject()` helper mapped to publish-subject validation |
|
||||
| `isValidLiteralSubject()` (tokens iter) | sublist.go:1241 | NOT_APPLICABLE | — | Takes `iter.Seq[string]` (Go 1.23 iterator); C# uses different iteration model |
|
||||
| `ValidateMapping()` | sublist.go:1258 | MISSING | — | Validates a mapping destination subject string including `{{function()}}` syntax; no public .NET equivalent |
|
||||
| `ValidateMapping()` | sublist.go:1258 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:138` | Added public destination-template validator with Go-compatible function parsing checks. |
|
||||
| `analyzeTokens()` | sublist.go:1298 | NOT_APPLICABLE | — | Internal helper used only in `SubjectsCollide()`; logic inlined in .NET `SubjectsCollide()` |
|
||||
| `tokensCanMatch()` | sublist.go:1314 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:199` (private `TokensCanMatch()`) | |
|
||||
| `SubjectsCollide()` | sublist.go:1326 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:159` | |
|
||||
| `numTokens()` | sublist.go:1374 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:118` (`NumTokens()`) | |
|
||||
| `tokenAt()` | sublist.go:1389 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:132` (`TokenAt()`) | Go is 1-based index; .NET is 0-based |
|
||||
| `tokenizeSubjectIntoSlice()` | sublist.go:1407 | NOT_APPLICABLE | — | Internal slice-reuse helper; .NET uses `Tokenize()` private method in SubList |
|
||||
| `SubjectMatchesFilter()` | sublist.go:1421 | PARTIAL | `src/NATS.Server/JetStream/Storage/MemStore.cs:1175` (private), `FileStore.cs:773` (private) | Duplicated as private methods in MemStore and FileStore; not a public standalone function |
|
||||
| `subjectIsSubsetMatch()` | sublist.go:1426 | MISSING | — | No public .NET equivalent; logic exists privately in MemStore/FileStore |
|
||||
| `isSubsetMatch()` | sublist.go:1434 | MISSING | — | Internal; no public .NET equivalent |
|
||||
| `isSubsetMatchTokenized()` | sublist.go:1444 | MISSING | — | Internal; no public .NET equivalent |
|
||||
| `SubjectMatchesFilter()` | sublist.go:1421 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:205`; consumers: `src/NATS.Server/JetStream/Storage/MemStore.cs:1175`, `src/NATS.Server/JetStream/Storage/FileStore.cs:773` | Added standalone `SubjectMatch.SubjectMatchesFilter()` and switched JetStream stores to use it. |
|
||||
| `subjectIsSubsetMatch()` | sublist.go:1426 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:207` (`SubjectIsSubsetMatch`) | Added direct port that tokenizes the subject and delegates to subset matching. |
|
||||
| `isSubsetMatch()` | sublist.go:1434 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:213` (`IsSubsetMatch`) | Added token-array vs test-subject subset matcher. |
|
||||
| `isSubsetMatchTokenized()` | sublist.go:1444 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:219` (`IsSubsetMatchTokenized`) | Added tokenized subset matcher with Go-compatible `*`/`>` handling. |
|
||||
| `matchLiteral()` | sublist.go:1483 | PORTED | `src/NATS.Server/Subscriptions/SubjectMatch.cs:75` (`MatchLiteral()`) | |
|
||||
| `addLocalSub()` | sublist.go:1552 | NOT_APPLICABLE | — | Filters by client kind (CLIENT/SYSTEM/JETSTREAM/ACCOUNT/LEAF); no .NET equivalent needed (client kind routing done elsewhere) |
|
||||
| `Sublist.addNodeToSubs()` | sublist.go:1562 | NOT_APPLICABLE | — | Internal helper for `localSubs()`; not ported |
|
||||
| `Sublist.collectLocalSubs()` | sublist.go:1581 | NOT_APPLICABLE | — | Internal helper for `localSubs()`; not ported |
|
||||
| `Sublist.localSubs()` | sublist.go:1597 | MISSING | — | Returns only local-client subscriptions (excludes routes/gateways); no .NET equivalent |
|
||||
| `Sublist.localSubs()` | sublist.go:1597 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:1015` | Added local-sub collector filtering to CLIENT/SYSTEM/JETSTREAM/ACCOUNT kinds with optional LEAF inclusion |
|
||||
| `Sublist.All()` | sublist.go:1604 | PORTED | `src/NATS.Server/Subscriptions/SubList.cs:712` | |
|
||||
| `Sublist.addAllNodeToSubs()` | sublist.go:1610 | NOT_APPLICABLE | — | Internal helper for `All()`; inlined in .NET |
|
||||
| `Sublist.collectAllSubs()` | sublist.go:1627 | NOT_APPLICABLE | — | Internal; inlined in `CollectAllSubs()` private method in .NET |
|
||||
@@ -182,26 +182,26 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| Transform type constants (`NoTransform`…`Random`) | subject_transform.go:43 | PARTIAL | `src/NATS.Server/Subscriptions/SubjectTransform.cs:682` (private `TransformType` enum) | `Random` (value 11 in Go) is absent from the .NET enum and switch statement; all others ported |
|
||||
| Transform type constants (`NoTransform`…`Random`) | subject_transform.go:43 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:794` (private `TransformType` enum) | Added `Random` transform type and execution branch parity. |
|
||||
| `subjectTransform` (struct) | subject_transform.go:61 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:11` | Internal fields mapped to `_source`, `_dest`, `_sourceTokens`, `_destTokens`, `_ops` |
|
||||
| `SubjectTransformer` (interface) | subject_transform.go:73 | NOT_APPLICABLE | — | Go exports interface for polymorphism; C# uses concrete `SubjectTransform` class directly |
|
||||
| `NewSubjectTransformWithStrict()` | subject_transform.go:81 | MISSING | — | Strict mode validates that all source wildcards are used in dest; no .NET equivalent |
|
||||
| `NewSubjectTransformWithStrict()` | subject_transform.go:81 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:126` | Added strict factory variant that rejects transforms when any source wildcard is unused by destination mapping. |
|
||||
| `NewSubjectTransform()` | subject_transform.go:198 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:31` (`Create()`) | Non-strict creation |
|
||||
| `NewSubjectTransformStrict()` | subject_transform.go:202 | MISSING | — | Strict version for import mappings; no .NET equivalent |
|
||||
| `NewSubjectTransformStrict()` | subject_transform.go:202 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:135` | Added strict convenience constructor delegating to strict factory mode. |
|
||||
| `getMappingFunctionArgs()` | subject_transform.go:206 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:639` (private `GetFunctionArgs()`) | |
|
||||
| `transformIndexIntArgsHelper()` | subject_transform.go:215 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:610` (private `ParseIndexIntArgs()`) | |
|
||||
| `indexPlaceHolders()` | subject_transform.go:237 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:486` (`ParseDestToken()` + `ParseMustacheToken()`) | Split into two methods; `Random` branch missing |
|
||||
| `transformTokenize()` | subject_transform.go:378 | MISSING | — | Converts `foo.*.*` to `foo.$1.$2`; used for import subject mapping reversal; no .NET equivalent |
|
||||
| `transformUntokenize()` | subject_transform.go:399 | MISSING | — | Inverse of above; used in `reverse()`; no .NET equivalent |
|
||||
| `indexPlaceHolders()` | subject_transform.go:237 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:586` (`ParseDestToken()` + `ParseMustacheToken()`) | Split into two methods, including `Random(...)` placeholder parsing branch. |
|
||||
| `transformTokenize()` | subject_transform.go:378 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:156` | Added wildcard tokenization helper converting `*` capture positions into `$N` placeholders. |
|
||||
| `transformUntokenize()` | subject_transform.go:399 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:173` | Added inverse helper converting `$N` placeholders back to `*` tokens. |
|
||||
| `tokenizeSubject()` | subject_transform.go:414 | NOT_APPLICABLE | — | Internal tokenizer; .NET uses `string.Split('.')` or `Tokenize()` private method |
|
||||
| `subjectTransform.Match()` | subject_transform.go:433 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:126` (`Apply()`) | Renamed; returns `null` instead of error on no-match |
|
||||
| `subjectTransform.TransformSubject()` | subject_transform.go:456 | PARTIAL | `src/NATS.Server/Subscriptions/SubjectTransform.cs:126` (via `Apply()`) | `TransformSubject` (apply without match check) not separately exposed; `Apply()` always checks match |
|
||||
| `subjectTransform.getRandomPartition()` | subject_transform.go:460 | MISSING | — | `Random` transform type not implemented in .NET |
|
||||
| `subjectTransform.TransformSubject()` | subject_transform.go:456 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:251` | Added dedicated transform-only entrypoint (`TransformSubject`) that applies destination mapping without source match guard. |
|
||||
| `subjectTransform.getRandomPartition()` | subject_transform.go:460 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:374` | Added random-partition helper and transform dispatch support (`random(n)` in range `[0,n)`, zero when `n<=0`). |
|
||||
| `subjectTransform.getHashPartition()` | subject_transform.go:469 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:226` (`ComputePartition()` + `Fnv1A32()`) | FNV-1a 32-bit hash ported |
|
||||
| `subjectTransform.TransformTokenizedSubject()` | subject_transform.go:482 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:144` (private `TransformTokenized()`) | All transform types except `Random` ported |
|
||||
| `subjectTransform.reverse()` | subject_transform.go:638 | MISSING | — | Produces the inverse transform; used for import subject mapping; no .NET equivalent |
|
||||
| `subjectTransform.TransformTokenizedSubject()` | subject_transform.go:482 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:261` (private `TransformTokenized()`) | Transform execution now includes `Random` and strict/helper parity branches. |
|
||||
| `subjectTransform.reverse()` | subject_transform.go:638 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:188` | Added inverse-transform builder for wildcard-mapped transforms used in import mapping reversal scenarios. |
|
||||
| `subjectInfo()` | subject_transform.go:666 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:451` (private `SubjectInfo()`) | |
|
||||
| `ValidateMapping()` (in subject_transform.go context) | sublist.go:1258 | MISSING | — | Also defined via `NewSubjectTransform`; validates mapping destination with function syntax; no .NET public equivalent |
|
||||
| `ValidateMapping()` (in subject_transform.go context) | sublist.go:1258 | PORTED | `src/NATS.Server/Subscriptions/SubjectTransform.cs:138` | Shared mapping validator exposed publicly and used for subject-transform destination validation parity. |
|
||||
|
||||
---
|
||||
|
||||
@@ -228,5 +228,9 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Executed subscriptions batch 4 subject-transform parity closures: added strict constructors (`NewSubjectTransformWithStrict`, `NewSubjectTransformStrict`), public mapping validator, random transform type/partition helper, tokenize/untokenize helpers, reverse-transform builder, and dedicated `TransformSubject` API with targeted tests (`SubjectTransformParityBatch3Tests`). | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Full gap inventory populated: analyzed sublist.go (~1,729 lines) and subject_transform.go (~689 lines) against all .NET Subscriptions/*.cs files. Counted 49 PORTED, 6 PARTIAL, 22 MISSING, 27 NOT_APPLICABLE, 0 DEFERRED. | claude-sonnet-4-6 |
|
||||
| 2026-02-25 | Executed subscriptions batch 1: added cache-mode constructors/factories and first/last-interest notification APIs to `SubList`, added subject helper aliases to `SubjectMatch`, added targeted tests (`SubListCtorAndNotificationParityTests`), and reclassified 7 rows (4 MISSING + 3 PARTIAL) to PORTED | codex |
|
||||
| 2026-02-25 | Executed subscriptions batch 2: added standalone subset/filter APIs to `SubjectMatch` (`SubjectMatchesFilter`, `SubjectIsSubsetMatch`, `IsSubsetMatch`, `IsSubsetMatchTokenized`), switched MemStore/FileStore subject filter helpers to use them, and added targeted tests (`SubjectSubsetMatchParityBatch1Tests`). Reclassified 4 open rows to PORTED. | codex |
|
||||
| 2026-02-25 | Executed subscriptions batch 3: added queue-scoped notification APIs, remote queue-weight updater, `SubListStats.Add`, trie depth helpers (`NumLevels`/`VisitLevel`), and local-sub collection (`LocalSubs`) with targeted tests (`SubListParityBatch2Tests`). Reclassified 7 open rows to PORTED. | codex |
|
||||
|
||||
@@ -132,7 +132,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| Server.reloadOCSP | golang/nats-server/server/ocsp.go:734 | MISSING | — | No OCSP hot-reload support |
|
||||
| hasOCSPStatusRequest | golang/nats-server/server/ocsp.go:804 | MISSING | — | No MustStaple TLS extension detection |
|
||||
| OCSPMonitor.writeOCSPStatus | golang/nats-server/server/ocsp.go:840 | MISSING | — | No atomic file write for OCSP status persistence |
|
||||
| parseCertPEM | golang/nats-server/server/ocsp.go:867 | PARTIAL | src/NATS.Server/Tls/TlsHelper.cs:17 | `LoadCaCertificates` uses `ImportFromPemFile` but does not validate PEM block type |
|
||||
| parseCertPEM | golang/nats-server/server/ocsp.go:867 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:33 | Added `ParseCertPem(string)` with explicit PEM block scanning/validation (`CERTIFICATE` only), multi-cert bundle parsing, and typed failures on unexpected block types. `LoadCaCertificates` now uses this parser. |
|
||||
| getOCSPIssuerLocally | golang/nats-server/server/ocsp.go:892 | MISSING | — | No local issuer resolution from cert bundle |
|
||||
| getOCSPIssuer | golang/nats-server/server/ocsp.go:932 | MISSING | — | No issuer resolution logic |
|
||||
| ocspStatusString | golang/nats-server/server/ocsp.go:968 | PORTED | src/NATS.Server/Events/EventTypes.cs:647 | `OcspEventBuilder.ParseStatus` and `OcspStatus` enum |
|
||||
@@ -142,7 +142,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| parseOCSPPeer | golang/nats-server/server/ocsp_peer.go:29 | MISSING | — | No config-file parsing for OCSP peer options |
|
||||
| parseOCSPPeer | golang/nats-server/server/ocsp_peer.go:29 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs:1101 | `ParseOcspPeer` supports short-form bool and long-form map parsing with Go-matching field names and conversion behavior |
|
||||
| peerFromVerifiedChains | golang/nats-server/server/ocsp_peer.go:130 | MISSING | — | No peer extraction from verified chains |
|
||||
| Server.plugTLSOCSPPeer | golang/nats-server/server/ocsp_peer.go:138 | PARTIAL | src/NATS.Server/Tls/TlsHelper.cs:36 | .NET uses X509RevocationMode.Online when OcspPeerVerify set; missing full OCSP peer plugin pattern with per-chain validation |
|
||||
| Server.plugClientTLSOCSPPeer | golang/nats-server/server/ocsp_peer.go:163 | PARTIAL | src/NATS.Server/Tls/TlsHelper.cs:41 | RemoteCertificateValidationCallback with revocation check, but no OCSP-specific chain walking or event publishing |
|
||||
@@ -213,34 +213,34 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| DefaultAllowedClockSkew | golang/nats-server/server/certidp/certidp.go:30 | MISSING | — | No OCSP clock skew constant |
|
||||
| DefaultOCSPResponderTimeout | golang/nats-server/server/certidp/certidp.go:31 | MISSING | — | No OCSP responder timeout constant |
|
||||
| DefaultTTLUnsetNextUpdate | golang/nats-server/server/certidp/certidp.go:32 | MISSING | — | No default TTL when NextUpdate is unset |
|
||||
| StatusAssertion (type) | golang/nats-server/server/certidp/certidp.go:35 | PARTIAL | src/NATS.Server/Events/EventTypes.cs:595 | `OcspStatus` enum exists (Good, Revoked, Unknown) but no JSON marshal/unmarshal or bidirectional maps |
|
||||
| GetStatusAssertionStr | golang/nats-server/server/certidp/certidp.go:56 | PORTED | src/NATS.Server/Events/EventTypes.cs:647 | `OcspEventBuilder.ParseStatus` provides string-to-enum; reverse mapping implicit |
|
||||
| ChainLink (struct) | golang/nats-server/server/certidp/certidp.go:93 | MISSING | — | No chain link struct with Leaf/Issuer/OCSPWebEndpoints |
|
||||
| OCSPPeerConfig (struct) | golang/nats-server/server/certidp/certidp.go:100 | MISSING | — | No OCSP peer config struct (Verify, Timeout, ClockSkew, WarnOnly, UnknownIsGood, AllowWhenCAUnreachable, TTLUnsetNextUpdate) |
|
||||
| NewOCSPPeerConfig | golang/nats-server/server/certidp/certidp.go:110 | MISSING | — | No peer config factory |
|
||||
| DefaultAllowedClockSkew | golang/nats-server/server/certidp/certidp.go:30 | PORTED | src/NATS.Server/Tls/OcspPeerConfig.cs:105 | `OCSPPeerConfig.DefaultAllowedClockSkew` set to 30 seconds |
|
||||
| DefaultOCSPResponderTimeout | golang/nats-server/server/certidp/certidp.go:31 | PORTED | src/NATS.Server/Tls/OcspPeerConfig.cs:106 | `OCSPPeerConfig.DefaultOCSPResponderTimeout` set to 2 seconds |
|
||||
| DefaultTTLUnsetNextUpdate | golang/nats-server/server/certidp/certidp.go:32 | PORTED | src/NATS.Server/Tls/OcspPeerConfig.cs:107 | `OCSPPeerConfig.DefaultTTLUnsetNextUpdate` set to 1 hour |
|
||||
| StatusAssertion (type) | golang/nats-server/server/certidp/certidp.go:35 | PORTED | src/NATS.Server/Tls/OcspPeerConfig.cs:9 | Added `StatusAssertion` enum with JSON converter and bidirectional string/int maps |
|
||||
| GetStatusAssertionStr | golang/nats-server/server/certidp/certidp.go:56 | PORTED | src/NATS.Server/Tls/OcspPeerConfig.cs:40 | `StatusAssertionMaps.GetStatusAssertionStr(int)` with unknown fallback |
|
||||
| ChainLink (struct) | golang/nats-server/server/certidp/certidp.go:93 | PORTED | src/NATS.Server/Tls/OcspPeerConfig.cs:81 | Added `ChainLink` type with `Leaf`, `Issuer`, and `OCSPWebEndpoints` |
|
||||
| OCSPPeerConfig (struct) | golang/nats-server/server/certidp/certidp.go:100 | PORTED | src/NATS.Server/Tls/OcspPeerConfig.cs:103 | Added `OCSPPeerConfig` with matching fields and defaults |
|
||||
| NewOCSPPeerConfig | golang/nats-server/server/certidp/certidp.go:110 | PORTED | src/NATS.Server/Tls/OcspPeerConfig.cs:117 | Added `OCSPPeerConfig.NewOCSPPeerConfig()` factory |
|
||||
| Log (struct) | golang/nats-server/server/certidp/certidp.go:123 | NOT_APPLICABLE | — | .NET uses ILogger<T> injection; no need for function-pointer log struct |
|
||||
| CertInfo (struct) | golang/nats-server/server/certidp/certidp.go:131 | MISSING | — | No cert info DTO for events |
|
||||
| GenerateFingerprint | golang/nats-server/server/certidp/certidp.go:179 | PARTIAL | src/NATS.Server/Tls/TlsHelper.cs:88 | `GetCertificateHash` uses SHA256 on SPKI (not raw cert as Go does); different hash input |
|
||||
| getWebEndpoints | golang/nats-server/server/certidp/certidp.go:184 | MISSING | — | No OCSP endpoint URL extraction/filtering |
|
||||
| GetSubjectDNForm | golang/nats-server/server/certidp/certidp.go:203 | MISSING | — | No subject RDN sequence formatting |
|
||||
| GetIssuerDNForm | golang/nats-server/server/certidp/certidp.go:212 | MISSING | — | No issuer RDN sequence formatting |
|
||||
| CertOCSPEligible | golang/nats-server/server/certidp/certidp.go:221 | MISSING | — | No OCSP eligibility check based on AIA extension |
|
||||
| GetLeafIssuerCert | golang/nats-server/server/certidp/certidp.go:237 | MISSING | — | No positional issuer extraction from chain |
|
||||
| OCSPResponseCurrent | golang/nats-server/server/certidp/certidp.go:250 | MISSING | — | No OCSP response currency check with clock skew and TTL fallback |
|
||||
| ValidDelegationCheck | golang/nats-server/server/certidp/certidp.go:288 | MISSING | — | No OCSP response delegation validation per RFC 6960 section 4.2.2.2 |
|
||||
| CertInfo (struct) | golang/nats-server/server/certidp/certidp.go:131 | PORTED | src/NATS.Server/Tls/OcspPeerConfig.cs:88 | Added `CertInfo` DTO with subject, issuer, fingerprint, and raw fields |
|
||||
| GenerateFingerprint | golang/nats-server/server/certidp/certidp.go:179 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:95 | Added `GenerateFingerprint` using SHA-256 of raw certificate bytes and base64 encoding |
|
||||
| getWebEndpoints | golang/nats-server/server/certidp/certidp.go:184 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:101 | Added `GetWebEndpoints` filtering to valid absolute HTTP/HTTPS URIs |
|
||||
| GetSubjectDNForm | golang/nats-server/server/certidp/certidp.go:203 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:117 | Added subject DN helper returning empty string for null cert |
|
||||
| GetIssuerDNForm | golang/nats-server/server/certidp/certidp.go:212 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:122 | Added issuer DN helper returning empty string for null cert |
|
||||
| CertOCSPEligible | golang/nats-server/server/certidp/certidp.go:221 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:142 | Added AIA OCSP responder extraction + HTTP(S) endpoint filtering, and populates `ChainLink.OCSPWebEndpoints` on success |
|
||||
| GetLeafIssuerCert | golang/nats-server/server/certidp/certidp.go:237 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:165 | Added positional issuer extraction helper (`leafPos + 1`) with bounds/self-signed guards |
|
||||
| OCSPResponseCurrent | golang/nats-server/server/certidp/certidp.go:250 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:193 | Added OCSP response currency window checks with configurable clock-skew and fallback TTL when `NextUpdate` is unset |
|
||||
| ValidDelegationCheck | golang/nats-server/server/certidp/certidp.go:288 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:224 | Added delegation validation: direct issuer response accepted, delegated responder requires OCSPSigning EKU |
|
||||
|
||||
### certidp/messages.go — CertIDP message types
|
||||
|
||||
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| Error message constants | golang/nats-server/server/certidp/messages.go:17 | MISSING | — | No equivalent error/debug message constants; .NET uses structured logging |
|
||||
| Debug message constants | golang/nats-server/server/certidp/messages.go:47 | MISSING | — | Debug format strings not ported; .NET logs differently |
|
||||
| MsgTLSClientRejectConnection | golang/nats-server/server/certidp/messages.go:81 | PARTIAL | src/NATS.Server/Events/EventTypes.cs:520 | Reject event type exists but literal reject reason string not exposed |
|
||||
| MsgTLSServerRejectConnection | golang/nats-server/server/certidp/messages.go:82 | PARTIAL | src/NATS.Server/Events/EventTypes.cs:520 | Same as above |
|
||||
| MsgCacheOnline / MsgCacheOffline | golang/nats-server/server/certidp/messages.go:96 | MISSING | — | No cache status notification messages |
|
||||
| Error message constants | golang/nats-server/server/certidp/messages.go:17 | PORTED | src/NATS.Server/Tls/OcspPeerMessages.cs:6 | Ported certidp error string constants (returned and directly-logged variants) into `OcspPeerMessages` |
|
||||
| Debug message constants | golang/nats-server/server/certidp/messages.go:47 | PORTED | src/NATS.Server/Tls/OcspPeerMessages.cs:36 | Ported certidp debug-format constants used by OCSP peer/cache workflows |
|
||||
| MsgTLSClientRejectConnection | golang/nats-server/server/certidp/messages.go:81 | PORTED | src/NATS.Server/Tls/OcspPeerMessages.cs:5 | Added literal reject reason constant for client OCSP validation failures |
|
||||
| MsgTLSServerRejectConnection | golang/nats-server/server/certidp/messages.go:82 | PORTED | src/NATS.Server/Tls/OcspPeerMessages.cs:6 | Added literal reject reason constant for server OCSP validation failures |
|
||||
| MsgCacheOnline / MsgCacheOffline | golang/nats-server/server/certidp/messages.go:96 | PORTED | src/NATS.Server/Tls/OcspPeerMessages.cs:7 | Added cache online/offline informational message templates |
|
||||
|
||||
### certidp/ocsp_responder.go — OCSP responder client
|
||||
|
||||
@@ -259,7 +259,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| MatchByMap | golang/nats-server/server/certstore/certstore.go:52 | NOT_APPLICABLE | — | .NET equivalent: X509FindType |
|
||||
| ParseCertStore | golang/nats-server/server/certstore/certstore.go:68 | NOT_APPLICABLE | — | .NET has built-in X509Store with StoreLocation |
|
||||
| ParseCertMatchBy | golang/nats-server/server/certstore/certstore.go:80 | NOT_APPLICABLE | — | .NET has X509FindType |
|
||||
| GetLeafIssuer | golang/nats-server/server/certstore/certstore.go:88 | MISSING | — | Could port using X509Chain verification to find issuer |
|
||||
| GetLeafIssuer | golang/nats-server/server/certstore/certstore.go:88 | PORTED | src/NATS.Server/Tls/TlsHelper.cs:176 | Added verified-chain issuer resolver using custom-root trust and returning chain element issuer |
|
||||
| credential (interface) | golang/nats-server/server/certstore/certstore.go:99 | NOT_APPLICABLE | — | .NET uses X509Certificate2 with private key; no separate credential interface needed |
|
||||
|
||||
### certstore/certstore_other.go — Non-Windows cert store stub
|
||||
@@ -336,5 +336,7 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Ported `parseCertPEM` parity by adding strict PEM certificate parser (`CERTIFICATE` blocks only), wiring `LoadCaCertificates` through it, and adding focused TLS helper tests for invalid block rejection and multi-cert bundles. | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Completed full gap inventory: 12 Go source files analyzed, 144 symbols classified (20 PORTED, 9 PARTIAL, 70 MISSING, 45 NOT_APPLICABLE, 0 DEFERRED) | claude-opus |
|
||||
| 2026-02-25 | Ported OCSP eligibility/issuer/currentness/delegation helpers, certstore leaf issuer resolution, and certidp error/debug message constants with targeted TLS/Ocsp parity tests | codex |
|
||||
|
||||
@@ -120,13 +120,13 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `parseSize` (unexported) | golang/nats-server/server/util.go:82 | PORTED | src/NATS.Server/Protocol/NatsParser.cs:434 | `NatsParser.ParseSize(Span<byte>)` — exact behavioral match including -1 on error; tested in InfrastructureGoParityTests |
|
||||
| `parseInt64` (unexported) | golang/nats-server/server/util.go:113 | PORTED | src/NATS.Server/Protocol/NatsParser.cs:434 | Folded into `ParseSize` / inline parser logic; behavior covered by parser tests |
|
||||
| `secondsToDuration` (unexported) | golang/nats-server/server/util.go:127 | NOT_APPLICABLE | — | Go-specific `time.Duration` helper; .NET uses `TimeSpan.FromSeconds(double)` directly |
|
||||
| `parseHostPort` (unexported) | golang/nats-server/server/util.go:134 | PARTIAL | src/NATS.Server/Configuration/ConfigProcessor.cs | ConfigProcessor parses `host:port` strings but does not have a standalone `ParseHostPort` helper matching Go's default-port fallback logic |
|
||||
| `parseHostPort` (unexported) | golang/nats-server/server/util.go:134 | PORTED | src/NATS.Server/Server/ServerUtilities.cs:19 | Added `ParseHostPort(string, int)` with default-port fallback and 0/-1 port normalization |
|
||||
| `urlsAreEqual` (unexported) | golang/nats-server/server/util.go:158 | NOT_APPLICABLE | — | Uses `reflect.DeepEqual` on `*url.URL`; not needed in .NET port (no equivalent URL gossip pattern yet) |
|
||||
| `comma` (unexported) | golang/nats-server/server/util.go:169 | PORTED | tests/NATS.Server.Tests/InfrastructureGoParityTests.cs:960 | Ported as `CommaFormat` helper in InfrastructureGoParityTests (test-side only); monitoring output uses `string.Format("{0:N0}")` in production |
|
||||
| `natsListenConfig` | golang/nats-server/server/util.go:246 | PORTED | src/NATS.Server/NatsServer.cs | .NET `TcpListener` / `Socket` used without OS TCP keepalives; keepalive is disabled by default in .NET socket setup matching Go behavior |
|
||||
| `natsListen` (unexported) | golang/nats-server/server/util.go:252 | PORTED | src/NATS.Server/NatsServer.cs | Equivalent accept loop uses `TcpListener.AcceptTcpClientAsync` without system keepalives |
|
||||
| `natsDialTimeout` (unexported) | golang/nats-server/server/util.go:258 | PARTIAL | src/NATS.Server/Routes/RouteConnection.cs | Route dialing exists but the explicit keepalive=-1 (disabled) setting is not verified in .NET route code |
|
||||
| `redactURLList` (unexported) | golang/nats-server/server/util.go:270 | PARTIAL | tests/NATS.Server.Tests/InfrastructureGoParityTests.cs:979 | `RedactUrl` helper ported in test file; no production-side `redactURLList` for URL slices |
|
||||
| `natsDialTimeout` (unexported) | golang/nats-server/server/util.go:258 | PORTED | src/NATS.Server/Routes/RouteManager.cs:547 | Added `CreateRouteDialSocket()` to explicitly disable TCP keepalive on outbound route dials before connect |
|
||||
| `redactURLList` (unexported) | golang/nats-server/server/util.go:270 | PORTED | src/NATS.Server/Server/ServerUtilities.cs:79 | Added production `RedactUrlList(IEnumerable<string>)` that redacts per-URL user-info passwords |
|
||||
| `redactURLString` (unexported) | golang/nats-server/server/util.go:296 | PORTED | tests/NATS.Server.Tests/InfrastructureGoParityTests.cs:979 | `RedactUrl` in InfrastructureGoParityTests matches behavior; also used in log redaction |
|
||||
| `getURLsAsString` (unexported) | golang/nats-server/server/util.go:308 | NOT_APPLICABLE | — | Internal URL slice utility for clustering; not needed in current .NET scope |
|
||||
| `copyBytes` (unexported) | golang/nats-server/server/util.go:317 | PORTED | (inline) | .NET uses `ReadOnlySpan<byte>.ToArray()`, `Array.Copy`, or `Buffer.BlockCopy` equivalently throughout the codebase |
|
||||
@@ -153,8 +153,8 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `rateCounter` (type) | golang/nats-server/server/rate_counter.go:21 | PORTED | src/NATS.Server/Tls/TlsRateLimiter.cs | `TlsRateLimiter` provides equivalent token-bucket rate limiting for TLS handshakes; also `ApiRateLimiter` for JetStream API |
|
||||
| `newRateCounter` | golang/nats-server/server/rate_counter.go:30 | PORTED | src/NATS.Server/Tls/TlsRateLimiter.cs:9 | `TlsRateLimiter(long tokensPerSecond)` constructor |
|
||||
| `rateCounter.allow` (unexported) | golang/nats-server/server/rate_counter.go:37 | PARTIAL | src/NATS.Server/Tls/TlsRateLimiter.cs:22 | `WaitAsync(CancellationToken)` is async/blocking rather than a synchronous allow-or-deny check; Go's `allow()` is non-blocking |
|
||||
| `rateCounter.countBlocked` (unexported) | golang/nats-server/server/rate_counter.go:58 | MISSING | — | No equivalent "count blocked requests" metric; `TlsRateLimiter` does not expose a blocked-count stat |
|
||||
| `rateCounter.allow` (unexported) | golang/nats-server/server/rate_counter.go:37 | PORTED | src/NATS.Server/Server/RateCounter.cs:21 | Added non-blocking `Allow()` with 1-second window and blocked-counter increment semantics |
|
||||
| `rateCounter.countBlocked` (unexported) | golang/nats-server/server/rate_counter.go:58 | PORTED | src/NATS.Server/Server/RateCounter.cs:42 | Added `CountBlocked()` that returns and resets blocked count |
|
||||
|
||||
### `golang/nats-server/server/sendq.go`
|
||||
|
||||
@@ -206,13 +206,13 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `ErrReservedPublishSubject` | golang/nats-server/server/errors.go:49 | PORTED | src/NATS.Server/NatsClient.cs | Reserved subject check on publish |
|
||||
| `ErrBadPublishSubject` | golang/nats-server/server/errors.go:52 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:28 | `ErrInvalidPublishSubject` constant |
|
||||
| `ErrBadSubject` | golang/nats-server/server/errors.go:55 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:29 | `ErrInvalidSubject` constant |
|
||||
| `ErrBadQualifier` | golang/nats-server/server/errors.go:58 | MISSING | — | No dedicated bad-qualifier error; transform validation throws `ArgumentException` |
|
||||
| `ErrBadQualifier` | golang/nats-server/server/errors.go:58 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:10 | Added parity literal constant for bad transform qualifier error |
|
||||
| `ErrBadClientProtocol` | golang/nats-server/server/errors.go:61 | PORTED | src/NATS.Server/NatsClient.cs | Protocol version validation on CONNECT |
|
||||
| `ErrTooManyConnections` | golang/nats-server/server/errors.go:64 | PORTED | src/NATS.Server/Protocol/NatsProtocol.cs:25 | `ErrMaxConnectionsExceeded` constant |
|
||||
| `ErrTooManyAccountConnections` | golang/nats-server/server/errors.go:68 | MISSING | — | Account-level connection limits not yet implemented |
|
||||
| `ErrTooManyAccountConnections` | golang/nats-server/server/errors.go:68 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:11 | Added parity error literal constant; enforcement work remains tracked separately in account-limit behavior gaps |
|
||||
| `ErrLeafNodeLoop` | golang/nats-server/server/errors.go:72 | PORTED | src/NATS.Server/LeafNode/ | Leaf node loop detection implemented |
|
||||
| `ErrTooManySubs` | golang/nats-server/server/errors.go:76 | MISSING | — | Per-connection subscription limit not yet enforced |
|
||||
| `ErrTooManySubTokens` | golang/nats-server/server/errors.go:79 | MISSING | — | Subject token count limit not yet enforced |
|
||||
| `ErrTooManySubs` | golang/nats-server/server/errors.go:76 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:12 | Added parity error literal constant |
|
||||
| `ErrTooManySubTokens` | golang/nats-server/server/errors.go:79 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:13 | Added parity error literal constant |
|
||||
| `ErrClientConnectedToRoutePort` | golang/nats-server/server/errors.go:83 | PORTED | src/NATS.Server/Routes/ | Wrong port detection on route listener |
|
||||
| `ErrClientConnectedToLeafNodePort` | golang/nats-server/server/errors.go:87 | PORTED | src/NATS.Server/LeafNode/ | Wrong port detection on leaf node listener |
|
||||
| `ErrLeafNodeHasSameClusterName` | golang/nats-server/server/errors.go:91 | PORTED | src/NATS.Server/LeafNode/ | Same-cluster-name rejection |
|
||||
@@ -220,22 +220,22 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `ErrConnectedToWrongPort` | golang/nats-server/server/errors.go:98 | PORTED | src/NATS.Server/NatsServer.cs | Port sniffing / wrong-port close |
|
||||
| `ErrAccountExists` | golang/nats-server/server/errors.go:102 | PORTED | src/NATS.Server/Auth/Account.cs | Duplicate account registration check |
|
||||
| `ErrBadAccount` | golang/nats-server/server/errors.go:105 | PORTED | src/NATS.Server/Auth/ | Bad/malformed account |
|
||||
| `ErrReservedAccount` | golang/nats-server/server/errors.go:108 | MISSING | — | Reserved account name check not yet implemented |
|
||||
| `ErrReservedAccount` | golang/nats-server/server/errors.go:108 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:14 | Added parity error literal constant |
|
||||
| `ErrMissingAccount` | golang/nats-server/server/errors.go:111 | PORTED | src/NATS.Server/Auth/ | Missing account lookup |
|
||||
| `ErrMissingService` | golang/nats-server/server/errors.go:114 | MISSING | — | Service export/import not yet ported |
|
||||
| `ErrBadServiceType` | golang/nats-server/server/errors.go:117 | MISSING | — | Service latency tracking not yet ported |
|
||||
| `ErrBadSampling` | golang/nats-server/server/errors.go:120 | MISSING | — | Latency sampling validation not yet ported |
|
||||
| `ErrMissingService` | golang/nats-server/server/errors.go:114 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:15 | Added parity error literal constant |
|
||||
| `ErrBadServiceType` | golang/nats-server/server/errors.go:117 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:16 | Added parity error literal constant |
|
||||
| `ErrBadSampling` | golang/nats-server/server/errors.go:120 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:17 | Added parity error literal constant |
|
||||
| `ErrAccountValidation` | golang/nats-server/server/errors.go:123 | PORTED | src/NATS.Server/Auth/ | Account validation logic |
|
||||
| `ErrAccountExpired` | golang/nats-server/server/errors.go:126 | PORTED | src/NATS.Server/Auth/ | Account expiry check |
|
||||
| `ErrNoAccountResolver` | golang/nats-server/server/errors.go:129 | PORTED | src/NATS.Server/Auth/ | No resolver configured check |
|
||||
| `ErrAccountResolverUpdateTooSoon` | golang/nats-server/server/errors.go:132 | MISSING | — | Resolver update rate limiting not yet ported |
|
||||
| `ErrAccountResolverSameClaims` | golang/nats-server/server/errors.go:135 | MISSING | — | Same-claims dedup not yet ported |
|
||||
| `ErrStreamImportAuthorization` | golang/nats-server/server/errors.go:138 | MISSING | — | Stream import auth not yet ported |
|
||||
| `ErrStreamImportBadPrefix` | golang/nats-server/server/errors.go:141 | MISSING | — | Stream import prefix validation not yet ported |
|
||||
| `ErrStreamImportDuplicate` | golang/nats-server/server/errors.go:144 | MISSING | — | Duplicate import detection not yet ported |
|
||||
| `ErrServiceImportAuthorization` | golang/nats-server/server/errors.go:147 | MISSING | — | Service import auth not yet ported |
|
||||
| `ErrImportFormsCycle` | golang/nats-server/server/errors.go:150 | MISSING | — | Import cycle detection not yet ported |
|
||||
| `ErrCycleSearchDepth` | golang/nats-server/server/errors.go:153 | MISSING | — | Cycle search depth limit not yet ported |
|
||||
| `ErrAccountResolverUpdateTooSoon` | golang/nats-server/server/errors.go:132 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:18 | Added parity error literal constant |
|
||||
| `ErrAccountResolverSameClaims` | golang/nats-server/server/errors.go:135 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:19 | Added parity error literal constant |
|
||||
| `ErrStreamImportAuthorization` | golang/nats-server/server/errors.go:138 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:20 | Added parity error literal constant |
|
||||
| `ErrStreamImportBadPrefix` | golang/nats-server/server/errors.go:141 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:21 | Added parity error literal constant |
|
||||
| `ErrStreamImportDuplicate` | golang/nats-server/server/errors.go:144 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:22 | Added parity error literal constant |
|
||||
| `ErrServiceImportAuthorization` | golang/nats-server/server/errors.go:147 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:23 | Added parity error literal constant |
|
||||
| `ErrImportFormsCycle` | golang/nats-server/server/errors.go:150 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:24 | Added parity error literal constant |
|
||||
| `ErrCycleSearchDepth` | golang/nats-server/server/errors.go:153 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:25 | Added parity error literal constant |
|
||||
| `ErrClientOrRouteConnectedToGatewayPort` | golang/nats-server/server/errors.go:157 | PORTED | src/NATS.Server/Gateways/ | Wrong port detection on gateway listener |
|
||||
| `ErrWrongGateway` | golang/nats-server/server/errors.go:161 | PORTED | src/NATS.Server/Gateways/ | Wrong gateway name on connect |
|
||||
| `ErrGatewayNameHasSpaces` | golang/nats-server/server/errors.go:165 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs | Config validation rejects spaces in gateway name |
|
||||
@@ -251,7 +251,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `ErrClusterNameHasSpaces` | golang/nats-server/server/errors.go:199 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs | Config validation |
|
||||
| `ErrMalformedSubject` | golang/nats-server/server/errors.go:202 | PORTED | src/NATS.Server/Subscriptions/SubjectMatch.cs | Subject validation rejects malformed subjects |
|
||||
| `ErrSubscribePermissionViolation` | golang/nats-server/server/errors.go:205 | PORTED | src/NATS.Server/NatsClient.cs | Subscribe permission check |
|
||||
| `ErrNoTransforms` | golang/nats-server/server/errors.go:208 | MISSING | — | Transform selection logic not yet fully ported |
|
||||
| `ErrNoTransforms` | golang/nats-server/server/errors.go:208 | PORTED | src/NATS.Server/Server/ServerErrorConstants.cs:26 | Added parity error literal constant |
|
||||
| `ErrCertNotPinned` | golang/nats-server/server/errors.go:211 | PORTED | src/NATS.Server/Tls/TlsHelper.cs | Pinned cert validation |
|
||||
| `ErrDuplicateServerName` | golang/nats-server/server/errors.go:215 | PORTED | src/NATS.Server/Routes/ | Duplicate server name on cluster connect |
|
||||
| `ErrMinimumVersionRequired` | golang/nats-server/server/errors.go:218 | PORTED | src/NATS.Server/Routes/ | Minimum version enforcement on cluster |
|
||||
@@ -270,11 +270,11 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `configErr` (type) | golang/nats-server/server/errors.go:261 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs:1434 | `ConfigProcessorException` with error list |
|
||||
| `configErr.Source` | golang/nats-server/server/errors.go:267 | PARTIAL | src/NATS.Server/Configuration/ConfigProcessor.cs | Source file/line tracking in errors is partial; exception message includes context but not file:line:col |
|
||||
| `configErr.Error` | golang/nats-server/server/errors.go:272 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs | Exception `Message` property |
|
||||
| `unknownConfigFieldErr` (type) | golang/nats-server/server/errors.go:280 | PARTIAL | src/NATS.Server/Configuration/ConfigProcessor.cs | Unknown fields trigger `ConfigProcessorException` but without the specific `unknownConfigFieldErr` type distinction |
|
||||
| `configWarningErr` (type) | golang/nats-server/server/errors.go:292 | MISSING | — | No distinction between warnings and errors in .NET config processor; all surfaced as exceptions |
|
||||
| `unknownConfigFieldErr` (type) | golang/nats-server/server/errors.go:280 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs:1597 | Added `UnknownConfigFieldWarning` type with field/source metadata and Go-style warning message (`unknown field <name>`). |
|
||||
| `configWarningErr` (type) | golang/nats-server/server/errors.go:292 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs:1588 | Added `ConfigWarningException` base warning type to distinguish warning payloads from hard errors. |
|
||||
| `processConfigErr` (type) | golang/nats-server/server/errors.go:303 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs:1434 | `ConfigProcessorException` accumulates all errors |
|
||||
| `processConfigErr.Error` | golang/nats-server/server/errors.go:310 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs | `Message` + `Errors` list |
|
||||
| `processConfigErr.Warnings` | golang/nats-server/server/errors.go:322 | MISSING | — | No separate warnings list; warnings folded into errors or logged |
|
||||
| `processConfigErr.Warnings` | golang/nats-server/server/errors.go:322 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs:1581 | Added `ConfigProcessorException.Warnings` list and wired unknown top-level field warnings into thrown config errors when validation errors are present. |
|
||||
| `processConfigErr.Errors` | golang/nats-server/server/errors.go:327 | PORTED | src/NATS.Server/Configuration/ConfigProcessor.cs:1437 | `ConfigProcessorException.Errors` property |
|
||||
| `errCtx` (type) | golang/nats-server/server/errors.go:332 | PORTED | tests/NATS.Server.Tests/InfrastructureGoParityTests.cs:1069 | `WrappedNatsException` (test-file-scoped) mirrors the error context wrapping; production code uses standard .NET exception chaining |
|
||||
| `NewErrorCtx` | golang/nats-server/server/errors.go:338 | PORTED | tests/NATS.Server.Tests/InfrastructureGoParityTests.cs:1069 | Equivalent via `new WrappedNatsException(inner, ctx)` in tests; production uses `new Exception(msg, inner)` |
|
||||
@@ -444,5 +444,7 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Ported config warning parity slice: added `ConfigWarningException`, `UnknownConfigFieldWarning`, and `ConfigProcessorException.Warnings`; wired unknown top-level fields as warning entries and added focused configuration parity tests. | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Full gap inventory populated — all Go source files analyzed, 131 symbols classified | auto |
|
||||
| 2026-02-25 | Ported missing `errors.go` parity literals into `ServerErrorConstants` and added targeted parity tests for the newly added constants | codex |
|
||||
|
||||
@@ -90,7 +90,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
|-----------|:-------------|--------|:----------------|-------|
|
||||
| `wsOpCode` (type) | websocket.go:41 | PORTED | `src/NATS.Server/WebSocket/WsConstants.cs:1` | Int constants replace Go type alias; `WsConstants.TextMessage`, `BinaryMessage`, etc. |
|
||||
| `websocket` (struct) | websocket.go:108 | PORTED | `src/NATS.Server/WebSocket/WsConnection.cs:8` | Fields mapped: `compress`, `maskread`/`maskwrite`, `browser`, `nocompfrag`. Cookie fields moved to `WsUpgradeResult`. `frames`/`fs` buffer management is now in `WsConnection.WriteAsync`. `compressor` (reuse) is NOT pooled — recreated per call. |
|
||||
| `srvWebsocket` (struct) | websocket.go:126 | PARTIAL | `src/NATS.Server/NatsServer.cs:538` | `_wsListener`, `_options.WebSocket` cover port/host/tls; `allowedOrigins` managed via `WsOriginChecker`. `connectURLsMap` ref-count URL set and `authOverride` flag are MISSING — not ported. |
|
||||
| `srvWebsocket` (struct) | websocket.go:126 | PARTIAL | `src/NATS.Server/NatsServer.cs:538` | `_wsListener`, `_options.WebSocket` cover port/host/tls; `allowedOrigins` managed via `WsOriginChecker`; explicit `authOverride` flag is now computed via `WsAuthConfig.Apply(...)`. `connectURLsMap` ref-count URL set is still missing. |
|
||||
| `allowedOrigin` (struct) | websocket.go:145 | PORTED | `src/NATS.Server/WebSocket/WsOriginChecker.cs:80` | Private `AllowedOrigin` record struct with `Scheme` and `Port`. |
|
||||
| `wsUpgradeResult` (struct) | websocket.go:150 | PORTED | `src/NATS.Server/WebSocket/WsUpgrade.cs:346` | `WsUpgradeResult` readonly record struct with equivalent fields. `kind` maps to `WsClientKind` enum. |
|
||||
| `wsReadInfo` (struct) | websocket.go:156 | PORTED | `src/NATS.Server/WebSocket/WsReadInfo.cs:10` | All fields ported: `rem`→`Remaining`, `fs`→`FrameStart`, `ff`→`FirstFrame`, `fc`→`FrameCompressed`, `mask`→`ExpectMask`, `mkpos`→`MaskKeyPos`, `mkey`→`MaskKey`, `cbufs`→`CompressedBuffers`, `coff`→`CompressedOffset`. Extra .NET fields added for control frame output. |
|
||||
@@ -104,7 +104,7 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `decompressorPool` | websocket.go:99 | PARTIAL | `src/NATS.Server/WebSocket/WsCompression.cs:193` | Go uses `sync.Pool` for `flate.Reader` reuse. .NET creates a new `DeflateStream` per decompression call — no pooling. Functional but slightly less efficient under high load. |
|
||||
| `compressLastBlock` | websocket.go:100 | PORTED | `src/NATS.Server/WebSocket/WsConstants.cs:62` | .NET uses 4-byte `DecompressTrailer` (sync marker only); Go uses 9-byte block. Both work correctly — difference is .NET `DeflateStream` does not need the final stored block. |
|
||||
| `wsGUID` | websocket.go:103 | PORTED | `src/NATS.Server/WebSocket/WsUpgrade.cs:177` | Inline string literal in `ComputeAcceptKey`. |
|
||||
| `wsTestRejectNoMasking` | websocket.go:106 | MISSING | — | Test-only hook to force masking rejection. No equivalent test hook in .NET. |
|
||||
| `wsTestRejectNoMasking` | websocket.go:106 | PORTED | `src/NATS.Server/WebSocket/WsUpgrade.cs:14` | Added test hook `RejectNoMaskingForTest`; when set, no-masking leaf upgrade requests are explicitly rejected |
|
||||
|
||||
#### Methods on `wsReadInfo`
|
||||
|
||||
@@ -148,16 +148,16 @@ Add rows to the Gap Inventory table below. Group by Go source file. Include the
|
||||
| `srvWebsocket.checkOrigin()` | websocket.go:933 | PORTED | `src/NATS.Server/WebSocket/WsOriginChecker.cs:32` | `WsOriginChecker.CheckOrigin()` — same-origin and allowed-list checks. Go checks `r.TLS != nil` for TLS detection; .NET uses `isTls` parameter passed at call site. |
|
||||
| `wsGetHostAndPort()` | websocket.go:985 | PORTED | `src/NATS.Server/WebSocket/WsOriginChecker.cs:65` | `WsOriginChecker.GetHostAndPort()` and `ParseHostPort()` — missing-port defaults to 80/443 by TLS flag. |
|
||||
| `wsAcceptKey()` | websocket.go:1004 | PORTED | `src/NATS.Server/WebSocket/WsUpgrade.cs:175` | `WsUpgrade.ComputeAcceptKey()` — SHA-1 of key + GUID, base64 encoded. |
|
||||
| `wsMakeChallengeKey()` | websocket.go:1011 | MISSING | — | Generates a random 16-byte base64 client key for outbound WS connections (leaf node acting as WS client). No .NET equivalent. Needed when .NET server connects outbound as a WS leaf. |
|
||||
| `validateWebsocketOptions()` | websocket.go:1020 | PARTIAL | `src/NATS.Server/WebSocket/WebSocketTlsConfig.cs:24` | `WebSocketTlsConfig.Validate()` checks cert+key pair consistency. Full Go validation (TLS required unless NoTLS, AllowedOrigins parseable, NoAuthUser in users list, Token/Username incompatible with users/nkeys, JWTCookie requires TrustedOperators, TLSPinnedCerts, reserved header names) is MISSING from .NET. |
|
||||
| `wsMakeChallengeKey()` | websocket.go:1011 | PORTED | `src/NATS.Server/WebSocket/WsUpgrade.cs:192` | Added `MakeChallengeKey()` generating a random base64-encoded 16-byte challenge nonce |
|
||||
| `validateWebsocketOptions()` | websocket.go:1020 | PORTED | `src/NATS.Server/WebSocket/WebSocketOptionsValidator.cs:11` | Added `WebSocketOptionsValidator.Validate(NatsOptions)` covering TLS cert/key requirement, allowed-origin URI parsing, `NoAuthUser` membership, username/token conflicts with users/nkeys, `JwtCookie` trusted-operator requirement, TLS pinned-cert validation, and reserved response-header protection. Startup now enforces this validation in `NatsServer.StartAsync()` before opening WS listener (`src/NATS.Server/NatsServer.cs:631`). |
|
||||
| `Server.wsSetOriginOptions()` | websocket.go:1083 | PARTIAL | `src/NATS.Server/WebSocket/WsUpgrade.cs:49` | Origin checking is constructed inline in `TryUpgradeAsync` from `options.SameOrigin` and `options.AllowedOrigins`. The Go method persists parsed origins in `srvWebsocket.allowedOrigins` map and supports hot-reload. .NET constructs a `WsOriginChecker` per request — no hot-reload support, but functionally equivalent for initial config. |
|
||||
| `Server.wsSetHeadersOptions()` | websocket.go:1111 | PORTED | `src/NATS.Server/WebSocket/WsUpgrade.cs:141` | Custom headers applied inline in `TryUpgradeAsync` from `options.Headers`. |
|
||||
| `Server.wsConfigAuth()` | websocket.go:1131 | MISSING | — | Sets `srvWebsocket.authOverride` flag based on username/token/noAuthUser presence. No equivalent flag computation in .NET — `WebSocketOptions` properties are read directly. Functionally equivalent but the explicit override flag is absent. |
|
||||
| `Server.wsConfigAuth()` | websocket.go:1131 | PORTED | `src/NATS.Server/WebSocket/WsAuthConfig.cs:5` | Added explicit auth-override computation (`Username`/`Token`/`NoAuthUser`) and startup application via `NatsServer.StartAsync()` before WS listener initialization |
|
||||
| `Server.startWebsocketServer()` | websocket.go:1137 | PORTED | `src/NATS.Server/NatsServer.cs:538` | `NatsServer.StartAsync()` section at line 538 sets up the WS listener, logs, and launches `RunWebSocketAcceptLoopAsync`. Go uses `http.Server` + mux; .NET uses raw `TcpListener`/`Socket.AcceptAsync`. LEAF and MQTT routing at connection time is PARTIAL — LEAF path is wired (`WsClientKind.Leaf`) but MQTT is not handled in `AcceptWebSocketClientAsync`. `lame-duck` / `ldmCh` signaling is MISSING. |
|
||||
| `Server.wsGetTLSConfig()` | websocket.go:1264 | PARTIAL | `src/NATS.Server/NatsServer.cs:807` | TLS is applied once at accept time via `TlsConnectionWrapper.NegotiateAsync`. Go uses `GetConfigForClient` callback for hot-reload TLS config. .NET does not support hot TLS config reload for WS. |
|
||||
| `Server.createWSClient()` | websocket.go:1273 | PORTED | `src/NATS.Server/NatsServer.cs:799` | `AcceptWebSocketClientAsync()` — creates `WsConnection`, constructs `NatsClient`, wires `IsWebSocket`/`WsInfo`, registers client. Go also sends INFO immediately and sets auth timer; .NET's `NatsClient.RunAsync()` handles INFO send and auth timer. |
|
||||
| `isWSURL()` | websocket.go:1544 | MISSING | — | Helper to detect `ws://` scheme in a URL. Used by leaf node / route URL parsing. No .NET equivalent — not yet needed since outbound WS connections are not implemented. |
|
||||
| `isWSSURL()` | websocket.go:1548 | MISSING | — | Helper to detect `wss://` scheme in a URL. Same as above — not yet needed. |
|
||||
| `isWSURL()` | websocket.go:1544 | PORTED | `src/NATS.Server/WebSocket/WsUpgrade.cs:203` | Added helper to detect absolute `ws://` URLs via URI scheme parsing |
|
||||
| `isWSSURL()` | websocket.go:1548 | PORTED | `src/NATS.Server/WebSocket/WsUpgrade.cs:215` | Added helper to detect absolute `wss://` URLs via URI scheme parsing |
|
||||
|
||||
---
|
||||
|
||||
@@ -184,5 +184,7 @@ After porting work is completed:
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|----|
|
||||
| 2026-02-26 | Ported `validateWebsocketOptions()` parity by adding `WebSocketOptionsValidator`, wiring startup enforcement, and adding focused validator tests including TLS pinned cert validation. | codex |
|
||||
| 2026-02-25 | Ported `Server.wsConfigAuth()` parity by adding `WsAuthConfig` auth-override computation and applying it during WS startup; added `WebSocketOptions.AuthOverride` plus focused tests. | codex |
|
||||
| 2026-02-25 | File created with LLM analysis instructions | auto |
|
||||
| 2026-02-25 | Full gap inventory populated: 37 Go symbols classified (26 PORTED, 7 PARTIAL, 4 MISSING, 0 NOT_APPLICABLE, 0 DEFERRED) | auto |
|
||||
|
||||
Reference in New Issue
Block a user