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

228 KiB
Raw Permalink Blame History

JetStream — Gap Analysis

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

LLM Instructions: How to Analyze This Category

Step 1: Read the Go Reference Files

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

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

Step 2: Read the .NET Implementation Files

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

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

Step 3: Cross-Reference Tests

Compare Go test functions against .NET test methods:

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

Step 4: Classify Each Item

Use these status values:

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

Step 5: Fill In the Gap Inventory

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

Key Porting Notes for JetStream

  • This is the largest module (55,228 Go source LOC, 30% ported). Break analysis into sub-areas:
    1. Core orchestration (jetstream.go, jetstream_api.go)
    2. Stream lifecycle (stream.go) — retention policies: Limits, Interest, WorkQueue
    3. Consumer state machine (consumer.go) — push vs pull, ack policies (None, All, Explicit)
    4. Storage engine (filestore.go, memstore.go) — S2 compression (IronSnappy NuGet), AEAD encryption (ChaCha20Poly1305/AesGcm)
    5. Cluster coordination (jetstream_cluster.go) — depends on RAFT module
  • Go's filestore.go alone is 12,600 lines — the single largest implementation file.
  • The storage interface (store.go) defines the contract; analyze this first to understand the abstraction.

Go Reference Files (Source)

  • golang/nats-server/server/jetstream.go — Orchestration, API subject handlers ($JS.API.*)
  • golang/nats-server/server/jetstream_api.go — JetStream API handlers (~5,300 lines)
  • golang/nats-server/server/jetstream_events.go — JetStream event publishing
  • golang/nats-server/server/jetstream_errors.go — Error definitions
  • golang/nats-server/server/jetstream_errors_generated.go — Generated error codes
  • golang/nats-server/server/jetstream_batching.go — Batch processing
  • golang/nats-server/server/jetstream_versioning.go — Version compatibility
  • golang/nats-server/server/stream.go — Stream lifecycle, retention policies (~8,000 lines)
  • golang/nats-server/server/consumer.go — Consumer state machine (~6,000 lines). Push vs pull, ack policies.
  • golang/nats-server/server/store.go — Storage abstraction interface
  • golang/nats-server/server/filestore.go — Block-based persistent storage (~12,600 lines). S2 compression, encryption.
  • golang/nats-server/server/memstore.go — In-memory storage with TTL
  • golang/nats-server/server/dirstore.go — Directory-based storage
  • golang/nats-server/server/disk_avail.go — Disk space checking
  • golang/nats-server/server/jetstream_cluster.go — Clustered JetStream (~10,900 lines)

Go Reference Files (Tests)

  • golang/nats-server/server/jetstream_test.go
  • golang/nats-server/server/jetstream_consumer_test.go
  • golang/nats-server/server/jetstream_errors_test.go
  • golang/nats-server/server/jetstream_batching_test.go
  • golang/nats-server/server/jetstream_versioning_test.go
  • golang/nats-server/server/jetstream_helpers_test.go
  • golang/nats-server/server/jetstream_jwt_test.go
  • golang/nats-server/server/jetstream_tpm_test.go
  • golang/nats-server/server/jetstream_sourcing_scaling_test.go
  • golang/nats-server/server/jetstream_benchmark_test.go
  • golang/nats-server/server/filestore_test.go
  • golang/nats-server/server/memstore_test.go
  • golang/nats-server/server/dirstore_test.go
  • golang/nats-server/server/store_test.go
  • golang/nats-server/server/jetstream_cluster_1_test.go through _4_test.go
  • golang/nats-server/server/jetstream_super_cluster_test.go
  • golang/nats-server/server/jetstream_leafnode_test.go
  • golang/nats-server/server/jetstream_cluster_long_test.go

.NET Implementation Files (Source)

  • src/NATS.Server/JetStream/ — Root files (orchestration)
  • src/NATS.Server/JetStream/Api/ — API handlers
  • src/NATS.Server/JetStream/Consumers/ — Consumer state machine
  • src/NATS.Server/JetStream/Models/ — StreamConfig, ConsumerConfig, etc.
  • src/NATS.Server/JetStream/MirrorSource/ — Stream mirroring & sourcing
  • src/NATS.Server/JetStream/Publish/ — Publish handling
  • src/NATS.Server/JetStream/Snapshots/ — State snapshots
  • src/NATS.Server/JetStream/Validation/ — Config validation
  • src/NATS.Server/JetStream/Storage/ — FileStore, MemStore, encryption
  • src/NATS.Server/JetStream/Cluster/ — Clustered JetStream

.NET Implementation Files (Tests)

  • tests/NATS.Server.Tests/JetStream/ — Root tests
  • tests/NATS.Server.Tests/JetStream/Api/
  • tests/NATS.Server.Tests/JetStream/Cluster/
  • tests/NATS.Server.Tests/JetStream/Consumers/
  • tests/NATS.Server.Tests/JetStream/MirrorSource/
  • tests/NATS.Server.Tests/JetStream/Snapshots/
  • tests/NATS.Server.Tests/JetStream/Storage/
  • tests/NATS.Server.Tests/JetStream/Streams/

Gap Inventory

jetstream.go — Core Orchestration (~2866 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
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 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
EnableJetStream (Server method) golang/nats-server/server/jetstream.go:188 PARTIAL src/NATS.Server/JetStream/JetStreamService.cs:95 StartAsync handles StoreDir creation and API subject registration. Missing: dynamic config, system memory detection, encryption init, cluster init
jsKeyGen (Server method) golang/nats-server/server/jetstream.go:240 MISSING HMAC-SHA256 key generation for JetStream encryption
decryptMeta (Server method) golang/nats-server/server/jetstream.go:257 MISSING Encrypted metafile decryption (AEAD with cipher fallback)
checkStoreDir (Server method) golang/nats-server/server/jetstream.go:320 MISSING Legacy store directory migration logic
initJetStreamEncryption (Server method) golang/nats-server/server/jetstream.go:382 MISSING TPM-backed encryption key initialization
enableJetStream (Server method) golang/nats-server/server/jetstream.go:414 PARTIAL src/NATS.Server/JetStream/JetStreamService.cs:95 Core startup covered. Missing: gcbOutMax, system account setup, JS banner, encryption notice, internal subscriptions setup, cluster mode init
canExtendOtherDomain (Server method) golang/nats-server/server/jetstream.go:533 MISSING Leaf node domain extension check
restartJetStream (Server method) golang/nats-server/server/jetstream.go:556 MISSING Re-enable JetStream during config reload
setupJetStreamExports (Server method) golang/nats-server/server/jetstream.go:590 MISSING System account service export setup
handleOutOfSpace (Server method) golang/nats-server/server/jetstream.go:613 MISSING OOS handling: disable JS + advisory
DisableJetStream (Server method) golang/nats-server/server/jetstream.go:643 PARTIAL src/NATS.Server/JetStream/JetStreamService.cs:141 DisposeAsync clears subjects. Missing: cluster meta leader transfer, RAFT node cleanup
enableJetStreamAccounts (Server method) golang/nats-server/server/jetstream.go:690 MISSING Multi-account JS enablement with parallel task workers
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 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 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
Account.UpdateJetStreamLimits golang/nats-server/server/jetstream.go:1736 MISSING Update account limits with delta checking
Account.JetStreamUsage golang/nats-server/server/jetstream.go:1834 MISSING Full account usage stats with tier breakdown
Account.DisableJetStream golang/nats-server/server/jetstream.go:1961 MISSING Per-account JS disable
Account.lookupStream golang/nats-server/server/jetstream.go:1717 MISSING Stream lookup by name (via jsa)
Account.streams / filteredStreams golang/nats-server/server/jetstream.go:1681 MISSING All/filtered stream enumeration
jsAccount.updateUsage golang/nats-server/server/jetstream.go:2187 MISSING Storage usage delta tracking
jsAccount.checkAndSyncUsage golang/nats-server/server/jetstream.go:2108 MISSING Usage drift detection and correction
jsAccount.sendClusterUsageUpdate golang/nats-server/server/jetstream.go:2250 MISSING Binary-encoded cluster usage publication
jsAccount.remoteUpdateUsage golang/nats-server/server/jetstream.go:2021 MISSING Process incoming remote usage updates
jetStream.wouldExceedLimits golang/nats-server/server/jetstream.go:2299 MISSING Server-level resource limit check
jetStream.checkLimits golang/nats-server/server/jetstream.go:2434 MISSING Account+server limit checking for stream config
jetStream.checkBytesLimits golang/nats-server/server/jetstream.go:2446 MISSING Byte-level limits check for mem/file storage
jetStream.sufficientResources golang/nats-server/server/jetstream.go:2549 MISSING System resource sufficiency check for new accounts
jetStream.reserveStreamResources golang/nats-server/server/jetstream.go:2606 MISSING Reserve MaxBytes for a stream
jetStream.releaseStreamResources golang/nats-server/server/jetstream.go:2627 MISSING Release reserved MaxBytes
jetStream.usageStats golang/nats-server/server/jetstream.go:2520 MISSING Server-wide JS usage stats
jsAccount.selectLimits golang/nats-server/server/jetstream.go:2337 MISSING Tier-based limit selection
jsAccount.storageTotals golang/nats-server/server/jetstream.go:2360 MISSING Aggregate mem/store totals
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 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 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
handleWritePermissionError (Server method) golang/nats-server/server/jetstream.go:2857 MISSING FS permission error handling

jetstream_api.go — API Handlers (~5165 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
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 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
JSApiStreamCreateResponse golang/nats-server/server/jetstream_api.go:415 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:94 StreamInfo returned. Missing: DidCreate field
JSApiStreamDeleteResponse golang/nats-server/server/jetstream_api.go:423 PORTED src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:17 Success field present
JSApiStreamInfoRequest / Response golang/nats-server/server/jetstream_api.go:434-446 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:94 Basic info works. Missing: DeletedDetails, SubjectsFilter, paged response
JSApiStreamNamesRequest / Response golang/nats-server/server/jetstream_api.go:453-467 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:11 StreamNames returned. Missing: paging, subject filter
JSApiStreamListRequest / Response golang/nats-server/server/jetstream_api.go:469-485 MISSING Detailed stream list with paging, missing/offline
JSApiStreamPurgeRequest / Response golang/nats-server/server/jetstream_api.go:492-507 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:76 Purge response with count. Missing: filter/sequence/keep options in request
JSApiStreamUpdateResponse golang/nats-server/server/jetstream_api.go:519 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:94 Returns StreamInfo. Response type constant missing
JSApiMsgDeleteRequest / Response golang/nats-server/server/jetstream_api.go:528-538 PORTED src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleMessageDelete implemented
JSApiStreamSnapshotRequest / Response golang/nats-server/server/jetstream_api.go:540-569 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:125 Basic snapshot modeled. Missing: DeliverSubject, NoConsumers, ChunkSize, WindowSize, CheckMsgs options
JSApiStreamRestoreRequest / Response golang/nats-server/server/jetstream_api.go:572-586 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleRestore exists. Missing: chunked delivery protocol
JSApiStreamRemovePeerRequest / Response golang/nats-server/server/jetstream_api.go:589-600 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ClusterControlApiHandlers.cs HandleStreamPeerRemove exists as stub
JSApiStreamLeaderStepDownResponse golang/nats-server/server/jetstream_api.go:603-608 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ClusterControlApiHandlers.cs HandleStreamLeaderStepdown exists
JSApiConsumerLeaderStepDownResponse golang/nats-server/server/jetstream_api.go:611-616 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ClusterControlApiHandlers.cs HandleConsumerLeaderStepdown exists
JSApiLeaderStepdownRequest / Response golang/nats-server/server/jetstream_api.go:619-629 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ClusterControlApiHandlers.cs HandleMetaLeaderStepdown exists
JSApiMetaServerRemoveRequest / Response golang/nats-server/server/jetstream_api.go:632-646 PARTIAL src/NATS.Server/JetStream/Api/Handlers/AccountControlApiHandlers.cs HandleServerRemove exists as stub
JSApiMetaServerStreamMoveRequest golang/nats-server/server/jetstream_api.go:650-659 PARTIAL src/NATS.Server/JetStream/Api/Handlers/AccountControlApiHandlers.cs HandleAccountStreamMove exists as stub
JSApiAccountPurgeResponse golang/nats-server/server/jetstream_api.go:663-667 PARTIAL src/NATS.Server/JetStream/Api/Handlers/AccountControlApiHandlers.cs HandleAccountPurge exists as stub
JSApiMsgGetRequest / Response golang/nats-server/server/jetstream_api.go:670-699 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleMessageGet exists. Missing: Batch, MaxBytes, StartTime, MultiLastFor, UpToSeq/Time, NoHeaders
JSApiConsumerCreateResponse golang/nats-server/server/jetstream_api.go:704-709 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:100 ConsumerInfo returned. Response type constant missing
JSApiConsumerDeleteResponse golang/nats-server/server/jetstream_api.go:711-716 PORTED src/NATS.Server/JetStream/Api/Handlers/ConsumerApiHandlers.cs HandleDelete implemented
JSApiConsumerPauseRequest / Response golang/nats-server/server/jetstream_api.go:718-729 PORTED src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:86 PauseResponse with Paused/PauseUntil
JSApiConsumerInfoResponse golang/nats-server/server/jetstream_api.go:731-736 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:100 ConsumerInfo returned. Missing: type field
JSApiConsumerNamesResponse golang/nats-server/server/jetstream_api.go:742-748 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiResponse.cs:12 ConsumerNames returned. Missing: paging
JSApiConsumerListResponse golang/nats-server/server/jetstream_api.go:750-758 MISSING Detailed consumer list with paging, missing/offline
JSApiConsumerGetNextRequest golang/nats-server/server/jetstream_api.go:761-768 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ConsumerApiHandlers.cs HandleNext exists. Missing: Expires, MaxBytes, Heartbeat, PriorityGroup
JSApiConsumerResetRequest / Response golang/nats-server/server/jetstream_api.go:771-781 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ConsumerApiHandlers.cs HandleReset exists as stub
JSApiConsumerUnpinRequest / Response golang/nats-server/server/jetstream_api.go:509-517 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ConsumerApiHandlers.cs HandleUnpin exists as stub
generateJSMappingTable golang/nats-server/server/jetstream_api.go:323-349 MISSING Domain prefix mapping table generation
apiDispatch (jetStream method) golang/nats-server/server/jetstream_api.go:795 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiRouter.cs:222 Router.Route matches subjects to handlers. Missing: ClientInfoHdr check, inflight tracking, queue-based dispatch pool
processJSAPIRoutedRequests golang/nats-server/server/jetstream_api.go:882 MISSING Worker pool goroutine for processing routed API requests
setJetStreamExportSubs golang/nats-server/server/jetstream_api.go:913 PARTIAL src/NATS.Server/JetStream/JetStreamService.cs:16 AllApiSubjects list covers subject registration. Missing: worker pool, Sublist-based routing
sendAPIResponse / sendAPIErrResponse golang/nats-server/server/jetstream_api.go:986-999 MISSING API response sending with audit advisory
sendJetStreamAPIAuditAdvisory golang/nats-server/server/jetstream_api.go:999+ MISSING JS API audit advisory publication
jsAccountInfoRequest golang/nats-server/server/jetstream_api.go:1238 PARTIAL src/NATS.Server/JetStream/Api/Handlers/AccountApiHandlers.cs HandleInfo returns basic counts. Missing: full JetStreamAccountStats
jsStreamCreateRequest golang/nats-server/server/jetstream_api.go:1335 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleCreate parses config and creates. Missing: clustered forwarding, permission checks, JSRequiredApiLevel header check
jsStreamUpdateRequest golang/nats-server/server/jetstream_api.go:1452 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleUpdate exists. Missing: config diff validation, clustered proposal
jsStreamNamesRequest golang/nats-server/server/jetstream_api.go:1557 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleNames returns list. Missing: paging, subject filter
jsStreamListRequest golang/nats-server/server/jetstream_api.go:1690 MISSING Detailed stream list with full StreamInfo per entry
jsStreamInfoRequest golang/nats-server/server/jetstream_api.go:1809 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleInfo returns config+state. Missing: subject detail paging, deleted details
jsStreamDeleteRequest golang/nats-server/server/jetstream_api.go:3073 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleDelete works. Missing: clustered forwarding
jsStreamPurgeRequest golang/nats-server/server/jetstream_api.go:3572 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandlePurge works. Missing: filter/sequence/keep options
jsMsgDeleteRequest golang/nats-server/server/jetstream_api.go:3147 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleMessageDelete works. Missing: NoErase option, clustered forwarding
jsMsgGetRequest golang/nats-server/server/jetstream_api.go:3272 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleMessageGet works for basic seq/subject. Missing: batch, multi-last, time-based queries
jsStreamSnapshotRequest golang/nats-server/server/jetstream_api.go:4007 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleSnapshot exists. Missing: chunk delivery, ack flow, window sizing
jsStreamRestoreRequest golang/nats-server/server/jetstream_api.go:3722 PARTIAL src/NATS.Server/JetStream/Api/Handlers/StreamApiHandlers.cs HandleRestore exists. Missing: chunk receive protocol
jsStreamLeaderStepDownRequest golang/nats-server/server/jetstream_api.go:2034 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ClusterControlApiHandlers.cs Stub exists
jsStreamRemovePeerRequest golang/nats-server/server/jetstream_api.go:2275 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ClusterControlApiHandlers.cs Stub exists
jsConsumerCreateRequest golang/nats-server/server/jetstream_api.go:4244 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ConsumerApiHandlers.cs HandleCreate works for basic cases. Missing: JSApiConsumerCreateEx subject parsing, action (Create/Update), config validation depth
jsConsumerNamesRequest golang/nats-server/server/jetstream_api.go:4470 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ConsumerApiHandlers.cs HandleNames works. Missing: paging
jsConsumerListRequest golang/nats-server/server/jetstream_api.go:4597 MISSING Detailed consumer list with paging
jsConsumerInfoRequest golang/nats-server/server/jetstream_api.go:4707 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ConsumerApiHandlers.cs HandleInfo returns config. Missing: full ConsumerInfo (delivered, ack_floor, num_ack_pending, etc.)
jsConsumerDeleteRequest golang/nats-server/server/jetstream_api.go:4913 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ConsumerApiHandlers.cs HandleDelete works
jsConsumerPauseRequest golang/nats-server/server/jetstream_api.go:4991 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ConsumerApiHandlers.cs HandlePause works. Missing: PauseRemaining duration in response
jsConsumerUnpinRequest golang/nats-server/server/jetstream_api.go:3429 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ConsumerApiHandlers.cs HandleUnpin exists as stub
jsLeaderServerRemoveRequest golang/nats-server/server/jetstream_api.go:2383 PARTIAL src/NATS.Server/JetStream/Api/Handlers/AccountControlApiHandlers.cs Stub exists
jsLeaderServerStreamMoveRequest golang/nats-server/server/jetstream_api.go:2514 PARTIAL src/NATS.Server/JetStream/Api/Handlers/AccountControlApiHandlers.cs Stub exists
jsLeaderServerStreamCancelMoveRequest golang/nats-server/server/jetstream_api.go:2678 PARTIAL src/NATS.Server/JetStream/Api/Handlers/AccountControlApiHandlers.cs Stub exists
jsLeaderAccountPurgeRequest golang/nats-server/server/jetstream_api.go:2793 PARTIAL src/NATS.Server/JetStream/Api/Handlers/AccountControlApiHandlers.cs Stub exists
jsLeaderStepDownRequest golang/nats-server/server/jetstream_api.go:2893 PARTIAL src/NATS.Server/JetStream/Api/Handlers/ClusterControlApiHandlers.cs Stub exists
delayedAPIResponder golang/nats-server/server/jetstream_api.go:1047 MISSING Delayed API response delivery with ordered linked list
JSDirectMsgGet handler golang/nats-server/server/jetstream_api.go:105-111 PARTIAL src/NATS.Server/JetStream/Api/Handlers/DirectApiHandlers.cs HandleGet exists. Missing: batch support, multi-last, header stripping
ILeaderForwarder interface PORTED src/NATS.Server/JetStream/Api/JetStreamApiRouter.cs:10 .NET-native abstraction for leader forwarding
JetStreamApiRouter PORTED src/NATS.Server/JetStream/Api/JetStreamApiRouter.cs:68 Subject-to-handler routing with leader check
ApiRateLimiter PORTED src/NATS.Server/JetStream/Api/ApiRateLimiter.cs:11 Concurrency limiter + dedup cache
ClusteredRequestProcessor PORTED src/NATS.Server/JetStream/Api/ClusteredRequestProcessor.cs:13 Pending request correlation with TCS pattern

jetstream_events.go — Advisory Event Types (~366 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
publishAdvisory (Server method) golang/nats-server/server/jetstream_events.go:23 PARTIAL src/NATS.Server/JetStream/Api/AdvisoryPublisher.cs:9 AdvisoryPublisher publishes via delegate. Missing: interest check (SubList.HasInterest), gateway interest check, system account fallback
JSAPIAudit (struct) golang/nats-server/server/jetstream_events.go:50 MISSING API audit advisory type with Server, Client, Subject, Request, Response, Domain
JSAPIAuditType (const) golang/nats-server/server/jetstream_events.go:60 MISSING "io.nats.jetstream.advisory.v1.api_audit"
ActionAdvisoryType (type + consts) golang/nats-server/server/jetstream_events.go:63-69 MISSING CreateEvent/DeleteEvent/ModifyEvent enum
JSStreamActionAdvisory (struct) golang/nats-server/server/jetstream_events.go:72 PARTIAL src/NATS.Server/JetStream/Api/AdvisoryPublisher.cs:28 StreamCreated/Deleted/Updated covered. Missing: Action field, Domain field, TypedEvent base
JSConsumerActionAdvisory (struct) golang/nats-server/server/jetstream_events.go:82 PARTIAL src/NATS.Server/JetStream/Api/AdvisoryPublisher.cs:75 ConsumerCreated/Deleted covered. Missing: Action field, Domain field
JSConsumerPauseAdvisory (struct) golang/nats-server/server/jetstream_events.go:93 MISSING Consumer pause/unpause advisory
JSConsumerAckMetric (struct) golang/nats-server/server/jetstream_events.go:106 MISSING Ack latency metric
JSConsumerDeliveryExceededAdvisory (struct) golang/nats-server/server/jetstream_events.go:122 MISSING Max delivery exceeded advisory
JSConsumerDeliveryNakAdvisory (struct) golang/nats-server/server/jetstream_events.go:135 MISSING NAK advisory
JSConsumerDeliveryTerminatedAdvisory (struct) golang/nats-server/server/jetstream_events.go:149 MISSING Terminated message advisory
JSSnapshotCreateAdvisory (struct) golang/nats-server/server/jetstream_events.go:166 MISSING Snapshot start advisory
JSSnapshotCompleteAdvisory (struct) golang/nats-server/server/jetstream_events.go:177 MISSING Snapshot complete advisory
JSRestoreCreateAdvisory (struct) golang/nats-server/server/jetstream_events.go:191 MISSING Restore start advisory
JSRestoreCompleteAdvisory (struct) golang/nats-server/server/jetstream_events.go:201 MISSING Restore complete advisory
JSDomainLeaderElectedAdvisory (struct) golang/nats-server/server/jetstream_events.go:221 MISSING Domain leader election advisory
JSStreamLeaderElectedAdvisory (struct) golang/nats-server/server/jetstream_events.go:233 MISSING Stream leader election advisory
JSStreamQuorumLostAdvisory (struct) golang/nats-server/server/jetstream_events.go:247 MISSING Stream quorum lost advisory
JSStreamBatchAbandonedAdvisory (struct) golang/nats-server/server/jetstream_events.go:259 MISSING Batch abandoned advisory
BatchAbandonReason (type + consts) golang/nats-server/server/jetstream_events.go:268-274 MISSING timeout/large/incomplete reasons
JSConsumerLeaderElectedAdvisory (struct) golang/nats-server/server/jetstream_events.go:280 MISSING Consumer leader election advisory
JSConsumerQuorumLostAdvisory (struct) golang/nats-server/server/jetstream_events.go:295 MISSING Consumer quorum lost advisory
JSConsumerGroupPinnedAdvisory (struct) golang/nats-server/server/jetstream_events.go:307 MISSING Priority group pin advisory
JSConsumerGroupUnpinnedAdvisory (struct) golang/nats-server/server/jetstream_events.go:320 MISSING Priority group unpin advisory
JSServerOutOfSpaceAdvisory (struct) golang/nats-server/server/jetstream_events.go:335 MISSING Server out of space advisory
JSServerRemovedAdvisory (struct) golang/nats-server/server/jetstream_events.go:348 MISSING Server removed advisory
JSAPILimitReachedAdvisory (struct) golang/nats-server/server/jetstream_events.go:360 MISSING API queue limit reached advisory

jetstream_errors.go — Error Framework (~103 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
ErrorIdentifier (type) golang/nats-server/server/jetstream_errors.go:29 MISSING uint16 error identifier type
ErrorOption / Unless golang/nats-server/server/jetstream_errors.go:12-19 MISSING Functional options for error creation
IsNatsErr golang/nats-server/server/jetstream_errors.go:32 MISSING Error identity checker by ErrorIdentifier
ApiError (struct) golang/nats-server/server/jetstream_errors.go:57 PARTIAL src/NATS.Server/JetStream/Api/JetStreamApiError.cs:3 Code + Description present. Missing: ErrCode (uint16 error code), Error() method
ErrorsData (struct) golang/nats-server/server/jetstream_errors.go:64 MISSING Source data for generated errors
ApiError.toReplacerArgs golang/nats-server/server/jetstream_errors.go:79 MISSING Template replacement helper

jetstream_errors_generated.go — Error Codes (~3176 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
ErrorIdentifier constants (200+) golang/nats-server/server/jetstream_errors_generated.go:7-400+ PARTIAL src/NATS.Server/JetStream/Publish/AtomicBatchPublishEngine.cs:14 Only 9 atomic-batch error codes ported. Missing: ~190 other error identifiers (stream, consumer, cluster, etc.)
ApiErrors map golang/nats-server/server/jetstream_errors_generated.go:400+ MISSING Global map[ErrorIdentifier]*ApiError with HTTP codes and descriptions
NewJS*Error factory functions (200+) golang/nats-server/server/jetstream_errors_generated.go:varies MISSING Factory functions for each error type with template substitution

jetstream_versioning.go — Version Negotiation (~237 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
JSApiLevel (const) golang/nats-server/server/jetstream_versioning.go:20 PORTED src/NATS.Server/JetStream/JsVersioning.cs:19 Value 3 matches
JSRequiredLevelMetadataKey (const) golang/nats-server/server/jetstream_versioning.go:22 PORTED src/NATS.Server/JetStream/JsVersioning.cs:25 "_nats.req.level"
JSServerVersionMetadataKey (const) golang/nats-server/server/jetstream_versioning.go:23 PORTED src/NATS.Server/JetStream/JsVersioning.cs:28 "_nats.ver"
JSServerLevelMetadataKey (const) golang/nats-server/server/jetstream_versioning.go:24 PORTED src/NATS.Server/JetStream/JsVersioning.cs:31 "_nats.level"
getRequiredApiLevel golang/nats-server/server/jetstream_versioning.go:28 PORTED src/NATS.Server/JetStream/JsVersioning.cs:37 Exact behavior match
supportsRequiredApiLevel golang/nats-server/server/jetstream_versioning.go:36 PORTED src/NATS.Server/JetStream/JsVersioning.cs:48 Exact behavior match
setStaticStreamMetadata golang/nats-server/server/jetstream_versioning.go:44 PORTED src/NATS.Server/JetStream/JsVersioning.cs:63 All feature level checks match (TTL, counter, batch, schedule, persist)
setDynamicStreamMetadata golang/nats-server/server/jetstream_versioning.go:88 PORTED src/NATS.Server/JetStream/JsVersioning.cs:101 Copy + add version/level
copyStreamMetadata golang/nats-server/server/jetstream_versioning.go:110 PORTED src/NATS.Server/JetStream/JsVersioning.cs:121 Copy versioning fields
setOrDeleteInStreamMetadata golang/nats-server/server/jetstream_versioning.go:118 PORTED src/NATS.Server/JetStream/JsVersioning.cs:197 Set or delete helper
setStaticConsumerMetadata golang/nats-server/server/jetstream_versioning.go:136 PORTED src/NATS.Server/JetStream/JsVersioning.cs:132 PauseUntil + priority checks match
setDynamicConsumerMetadata golang/nats-server/server/jetstream_versioning.go:164 PORTED src/NATS.Server/JetStream/JsVersioning.cs:157 Copy + add version/level
setDynamicConsumerInfoMetadata golang/nats-server/server/jetstream_versioning.go:181 MISSING Wraps setDynamicConsumerMetadata for ConsumerInfo
copyConsumerMetadata golang/nats-server/server/jetstream_versioning.go:198 PORTED src/NATS.Server/JetStream/JsVersioning.cs:176 Copy versioning fields
setOrDeleteInConsumerMetadata golang/nats-server/server/jetstream_versioning.go:206 PORTED src/NATS.Server/JetStream/JsVersioning.cs:213 Set or delete helper
deleteDynamicMetadata golang/nats-server/server/jetstream_versioning.go:222 PORTED src/NATS.Server/JetStream/JsVersioning.cs:187 Remove version/level keys
errorOnRequiredApiLevel golang/nats-server/server/jetstream_versioning.go:229 MISSING Header-based API level rejection check

jetstream_batching.go — Batch Operations (~663 lines)

Go Symbol Go File:Line Status .NET Equivalent Notes
globalInflightBatches (var) golang/nats-server/server/jetstream_batching.go:31 MISSING Global atomic counter across all streams
batching (struct) golang/nats-server/server/jetstream_batching.go:35 PARTIAL src/NATS.Server/JetStream/Publish/AtomicBatchPublishEngine.cs:91 AtomicBatchPublishEngine uses ConcurrentDictionary. Missing: per-group store, timer-based cleanup
batchGroup (struct) golang/nats-server/server/jetstream_batching.go:40 PARTIAL src/NATS.Server/JetStream/Publish/AtomicBatchPublishEngine.cs:61 InFlightBatch tracks messages. Missing: lseq, store (StreamStore), timer
batchGroup.newBatchGroup golang/nats-server/server/jetstream_batching.go:47 PARTIAL src/NATS.Server/JetStream/Publish/AtomicBatchPublishEngine.cs:150 Batch creation in Process(). Missing: per-batch file store, server-configured timeout
getBatchStoreDir golang/nats-server/server/jetstream_batching.go:66 MISSING Compute batch store directory path
newBatchStore golang/nats-server/server/jetstream_batching.go:79 MISSING Create file or memory store for batch staging
batchGroup.readyForCommit golang/nats-server/server/jetstream_batching.go:104 PARTIAL src/NATS.Server/JetStream/Publish/AtomicBatchPublishEngine.cs:258 Commit path exists. Missing: timer.Stop() check, FlushAllPending
batchGroup.cleanup / cleanupLocked golang/nats-server/server/jetstream_batching.go:113-125 PARTIAL src/NATS.Server/JetStream/Publish/AtomicBatchPublishEngine.cs:317 EvictExpiredBatches. Missing: store.Delete, globalInflightBatches decrement
batchGroup.stopLocked golang/nats-server/server/jetstream_batching.go:128 MISSING Stop batch without cleanup
batchStagedDiff (struct) golang/nats-server/server/jetstream_batching.go:135 MISSING Staged diff for consistency checks: msgIds, counter, inflight, expectedPerSubject
batchStagedDiff.commit golang/nats-server/server/jetstream_batching.go:147 MISSING Commit staged diff to stream state
batchApply (struct) golang/nats-server/server/jetstream_batching.go:198 MISSING Cluster-level batch apply state
batchApply.clearBatchStateLocked golang/nats-server/server/jetstream_batching.go:209 MISSING Clear in-memory batch state
batchApply.rejectBatchStateLocked golang/nats-server/server/jetstream_batching.go:220 MISSING Reject batch and adjust CLFS
checkMsgHeadersPreClusteredProposal golang/nats-server/server/jetstream_batching.go:240 MISSING Pre-proposal header validation (~420 lines): expected-seq, per-subject-seq, msg ID dedup, counter CRDT, TTL, scheduling, rollup, discard-new checks
AtomicBatchPublishEngine (.NET-only) PORTED src/NATS.Server/JetStream/Publish/AtomicBatchPublishEngine.cs:91 .NET-native batch engine with stage/commit/error flow
AtomicBatchPublishErrorCodes (.NET-only) PORTED src/NATS.Server/JetStream/Publish/AtomicBatchPublishEngine.cs:14 9 error codes matching Go generated codes
BatchPublishRequest (.NET-only) PORTED src/NATS.Server/JetStream/Publish/AtomicBatchPublishEngine.cs:331 Request model for batch messages
AtomicBatchResult (.NET-only) PORTED src/NATS.Server/JetStream/Publish/AtomicBatchPublishEngine.cs:358 Staged/Committed/Error result type

Keeping This File Updated

After porting work is completed:

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

| StorageType (enum: FileStorage, MemoryStorage) | store.go:30-38 | PORTED | Models/StreamConfig.cs StorageType enum + Models/JetStreamPolicies.cs | Values mapped as Memory/File | | ErrStoreClosed | store.go:42 | MISSING | — | No sentinel error constants defined in .NET storage layer | | ErrStoreMsgNotFound | store.go:44 | MISSING | — | Same | | ErrStoreEOF | store.go:46 | MISSING | — | Same | | ErrMaxMsgs | store.go:48 | MISSING | — | Same | | ErrMaxBytes | store.go:50 | MISSING | — | Same | | ErrMaxMsgsPerSubject | store.go:52 | MISSING | — | Same | | ErrStoreSnapshotInProgress | store.go:55 | MISSING | — | Same | | ErrMsgTooLarge | store.go:57 | MISSING | — | Same | | ErrStoreWrongType | store.go:59 | MISSING | — | Same | | ErrNoAckPolicy | store.go:61 | MISSING | — | Same | | ErrSequenceMismatch | store.go:63 | MISSING | — | Same | | ErrCorruptStreamState | store.go:65 | MISSING | — | Same | | ErrTooManyResults | store.go:67 | MISSING | — | Same | | StoreMsg (struct) | store.go:71-78 | PORTED | Storage/StoreMsg.cs | Class with Subject, Header, Data, Sequence, Timestamp; Clear() matches Go's clear() | | StoreMsg.copy() | store.go:740-748 | MISSING | — | No buffer-reuse copy semantics; .NET class doesn't pool backing buffer | | StoreMsg.clear() | store.go:751-759 | PORTED | StoreMsg.Clear() | Simplified — no backing buffer pool | | StorageUpdateHandler (callback) | store.go:82-83 | MISSING | — | No callback registration model in .NET IStreamStore | | StorageRemoveMsgHandler (callback) | store.go:85 | MISSING | — | Same | | ProcessJetStreamMsgHandler (callback) | store.go:89 | MISSING | — | Same | | StreamStore (interface) | store.go:91-135 | PORTED | Storage/IStreamStore.cs | All 34 Go methods have signatures; default implementations throw NotSupportedException | | StreamStore.StoreMsg | store.go:92 | PORTED | IStreamStore.StoreMsg | Signature matches | | StreamStore.StoreRawMsg | store.go:93 | PORTED | IStreamStore.StoreRawMsg | Signature matches | | StreamStore.SkipMsg | store.go:94 | PORTED | IStreamStore.SkipMsg | Returns ulong only (Go returns (uint64, error)) | | StreamStore.SkipMsgs | store.go:95 | PORTED | IStreamStore.SkipMsgs | Signature matches | | StreamStore.FlushAllPending | store.go:96 | PORTED | IStreamStore.FlushAllPending | Returns Task (async adaptation) | | StreamStore.LoadMsg | store.go:97 | PORTED | IStreamStore.LoadMsg | Signature matches | | StreamStore.LoadNextMsg | store.go:98 | PORTED | IStreamStore.LoadNextMsg | Returns tuple (StoreMsg, ulong Skip) | | StreamStore.LoadNextMsgMulti | store.go:99 | MISSING | — | gsl.SimpleSublist not ported; no multi-filter load | | StreamStore.LoadLastMsg | store.go:100 | PORTED | IStreamStore.LoadLastMsg | Signature matches | | StreamStore.LoadPrevMsg | store.go:101 | PORTED | IStreamStore.LoadPrevMsg | Signature matches | | StreamStore.LoadPrevMsgMulti | store.go:102 | MISSING | — | gsl.SimpleSublist not ported | | StreamStore.RemoveMsg | store.go:103 | PORTED | IStreamStore.RemoveMsg | Returns bool only (Go returns (bool, error)) | | StreamStore.EraseMsg | store.go:104 | PORTED | IStreamStore.EraseMsg | Same note | | StreamStore.Purge | store.go:105 | PORTED | IStreamStore.Purge | Returns ulong only | | StreamStore.PurgeEx | store.go:106 | PORTED | IStreamStore.PurgeEx | Signature matches | | StreamStore.Compact | store.go:107 | PORTED | IStreamStore.Compact | Signature matches | | StreamStore.Truncate | store.go:108 | PORTED | IStreamStore.Truncate | Void (Go returns error) | | StreamStore.GetSeqFromTime | store.go:109 | PORTED | IStreamStore.GetSeqFromTime | Uses DateTime instead of time.Time | | StreamStore.FilteredState | store.go:110 | PORTED | IStreamStore.FilteredState | Signature matches | | StreamStore.SubjectsState | store.go:111 | PORTED | IStreamStore.SubjectsState | Returns Dictionary<string, SimpleState> | | StreamStore.SubjectsTotals | store.go:112 | PORTED | IStreamStore.SubjectsTotals | Returns Dictionary<string, ulong> | | StreamStore.AllLastSeqs | store.go:113 | PORTED | IStreamStore.AllLastSeqs | Returns ulong[] | | StreamStore.MultiLastSeqs | store.go:114 | PORTED | IStreamStore.MultiLastSeqs | Signature matches | | StreamStore.SubjectForSeq | store.go:115 | PORTED | IStreamStore.SubjectForSeq | Signature matches | | StreamStore.NumPending | store.go:116 | PORTED | IStreamStore.NumPending | Returns tuple (ulong Total, ulong ValidThrough) | | StreamStore.NumPendingMulti | store.go:117 | MISSING | — | gsl.SimpleSublist not ported | | StreamStore.State | store.go:118 | PORTED | IStreamStore.State | Returns Storage.StreamState | | StreamStore.FastState | store.go:119 | PORTED | IStreamStore.FastState(ref) | Uses ref parameter | | StreamStore.EncodedStreamState | store.go:120 | PORTED | IStreamStore.EncodedStreamState | Signature matches | | StreamStore.SyncDeleted | store.go:121 | MISSING | — | DeleteBlocks interface not ported | | StreamStore.Type | store.go:122 | PORTED | IStreamStore.Type | Signature matches | | StreamStore.RegisterStorageUpdates | store.go:123 | MISSING | — | No callback registration | | StreamStore.RegisterStorageRemoveMsg | store.go:124 | MISSING | — | No callback registration | | StreamStore.RegisterProcessJetStreamMsg | store.go:125 | MISSING | — | No callback registration | | StreamStore.UpdateConfig | store.go:126 | PORTED | IStreamStore.UpdateConfig | Signature matches | | StreamStore.Delete | store.go:127 | PORTED | IStreamStore.Delete | Signature matches | | StreamStore.Stop | store.go:128 | PORTED | IStreamStore.Stop | Signature matches | | StreamStore.ConsumerStore | store.go:129 | PORTED | IStreamStore.ConsumerStore | Returns IConsumerStore | | StreamStore.AddConsumer | store.go:130 | MISSING | — | Not in IStreamStore | | StreamStore.RemoveConsumer | store.go:131 | MISSING | — | Not in IStreamStore | | StreamStore.Snapshot | store.go:132 | PARTIAL | Snapshots/StreamSnapshotService.cs | TAR+S2 snapshot exists but not on IStreamStore interface; different signature | | StreamStore.Utilization | store.go:133 | MISSING | — | Not in IStreamStore | | StreamStore.ResetState | store.go:134 | PORTED | IStreamStore.ResetState | Signature matches | | RetentionPolicy (enum) | store.go:137-148 | PORTED | Models/JetStreamPolicies.cs RetentionPolicy | Limits, Interest, WorkQueue | | RetentionPolicy.String() | store.go:478-489 | NOT_APPLICABLE | — | .NET enum has ToString() by default | | RetentionPolicy.MarshalJSON | store.go:491-502 | NOT_APPLICABLE | — | System.Text.Json handles enum serialization | | RetentionPolicy.UnmarshalJSON | store.go:504-516 | NOT_APPLICABLE | — | Same | | DiscardPolicy (enum) | store.go:152-159 | PORTED | Models/JetStreamPolicies.cs DiscardPolicy | Old, New | | DiscardPolicy.String/MarshalJSON/UnmarshalJSON | store.go:518-550 | NOT_APPLICABLE | — | Handled by System.Text.Json | | StorageType.String/MarshalJSON/UnmarshalJSON | store.go:562-594 | NOT_APPLICABLE | — | Handled by System.Text.Json | | AckPolicy (enum: AckNone, AckAll, AckExplicit) | store.go:596-633 | PORTED | Models/ConsumerConfig.cs AckPolicy | None, Explicit, All | | AckPolicy.MarshalJSON/UnmarshalJSON | store.go:608-633 | NOT_APPLICABLE | — | Handled by System.Text.Json | | ReplayPolicy (enum) | store.go:635-666 | PORTED | Models/JetStreamPolicies.cs ReplayPolicy | Instant, Original | | ReplayPolicy.MarshalJSON/UnmarshalJSON | store.go:645-666 | NOT_APPLICABLE | — | Same | | DeliverPolicy (enum) | store.go:668-726 | PORTED | Models/JetStreamPolicies.cs DeliverPolicy | All, Last, New, ByStartSequence, ByStartTime, LastPerSubject | | DeliverPolicy.MarshalJSON/UnmarshalJSON | store.go:688-726 | NOT_APPLICABLE | — | Same | | StreamState (struct) | store.go:162-175 | PORTED | Storage/StreamState.cs | record struct with all fields | | SimpleState (struct) | store.go:178-187 | PORTED | Storage/StreamState.cs | record struct; internal firstNeedsUpdate/lastNeedsUpdate fields not ported | | LostStreamData (struct) | store.go:190-193 | PORTED | Storage/StreamState.cs LostStreamData class | Msgs and Bytes fields | | SnapshotResult (struct) | store.go:196-200 | PARTIAL | Snapshots/StreamSnapshotService.cs SnapshotRestoreResult | Different shape; no Reader/errCh; restore-oriented | | Stream state encoding constants | store.go:202-211 | PARTIAL | Storage/ConsumerStateCodec.cs | Magic/version constants exist for consumer state; stream state encoding constants not in dedicated file | | DeleteBlock (interface) | store.go:218-221 | MISSING | — | Not ported | | DeleteBlocks (slice type) | store.go:223 | MISSING | — | Not ported | | StreamReplicatedState (struct) | store.go:227-234 | MISSING | — | Not ported as standalone type | | IsEncodedStreamState() | store.go:237-239 | MISSING | — | Not ported | | DecodeStreamState() | store.go:243-305 | MISSING | — | Not ported | | DeleteRange (struct + methods) | store.go:308-328 | MISSING | — | Not ported | | DeleteSlice (type + methods) | store.go:331-347 | MISSING | — | Not ported | | DeleteBlocks.NumDeleted() | store.go:349-355 | MISSING | — | Not ported | | ConsumerStore (interface) | store.go:358-374 | PORTED | Storage/IConsumerStore.cs | All 13 methods ported | | ConsumerStore.SetStarting | store.go:359 | PORTED | IConsumerStore.SetStarting | Void (Go returns error) | | ConsumerStore.UpdateStarting | store.go:360 | PORTED | IConsumerStore.UpdateStarting | Matches | | ConsumerStore.Reset | store.go:361 | PORTED | IConsumerStore.Reset | Void (Go returns error) | | ConsumerStore.HasState | store.go:362 | PORTED | IConsumerStore.HasState | Matches | | ConsumerStore.UpdateDelivered | store.go:363 | PORTED | IConsumerStore.UpdateDelivered | Void (Go returns error) | | ConsumerStore.UpdateAcks | store.go:364 | PORTED | IConsumerStore.UpdateAcks | Void (Go returns error) | | ConsumerStore.UpdateConfig | store.go:365 | MISSING | — | Not on IConsumerStore | | ConsumerStore.Update | store.go:366 | PORTED | IConsumerStore.Update | Matches | | ConsumerStore.State | store.go:367 | PORTED | IConsumerStore.State | Returns ConsumerState (Go returns (*ConsumerState, error)) | | ConsumerStore.BorrowState | store.go:368 | PORTED | IConsumerStore.BorrowState | Matches | | ConsumerStore.EncodedState | store.go:369 | PORTED | IConsumerStore.EncodedState | Returns byte[] | | ConsumerStore.Type | store.go:370 | PORTED | IConsumerStore.Type | Matches | | ConsumerStore.Stop | store.go:371 | PORTED | IConsumerStore.Stop | Matches | | ConsumerStore.Delete | store.go:372 | PORTED | IConsumerStore.Delete | Matches | | ConsumerStore.StreamDelete | store.go:373 | PORTED | IConsumerStore.StreamDelete | Matches | | SequencePair (struct) | store.go:377-380 | PORTED | Storage/ConsumerState.cs SequencePair | record struct | | ConsumerState (struct) | store.go:383-394 | PORTED | Storage/ConsumerState.cs | Class with Delivered, AckFloor, Pending, Redelivered | | Pending (struct) | store.go:461-464 | PORTED | Storage/ConsumerState.cs Pending | record struct | | encodeConsumerState() | store.go:397-457 | PORTED | Storage/ConsumerStateCodec.Encode() | Wire-compatible binary encoding | | isOutOfSpaceErr() | store.go:728-730 | MISSING | — | No dedicated helper | | errFirstSequenceMismatch | store.go:733 | MISSING | — | Not ported | | isClusterResetErr() | store.go:735-737 | MISSING | — | Not ported | | bytesToString() | store.go:763-769 | NOT_APPLICABLE | — | .NET strings are native; no unsafe cast needed | | stringToBytes() | store.go:772-778 | NOT_APPLICABLE | — | Same | | copyString() | store.go:783-787 | NOT_APPLICABLE | — | .NET strings are immutable; always safe | | isPermissionError() | store.go:789-791 | MISSING | — | No dedicated helper |

| StreamConfigRequest | stream.go:41-46 | MISSING | — | No Pedantic field in .NET; validation is in JetStreamConfigValidator | | StreamConfig (struct, ~80 fields) | stream.go:50-125 | PARTIAL | Models/StreamConfig.cs | Core fields ported; missing: NoAck, Placement, Compression, MirrorDirect, DiscardNewPer, AllowRollup, ConsumerLimits, Mirror as StreamSource (simplified to string), Sources as []*StreamSource (simplified) | | StreamConfig.clone() | stream.go:129-161 | PARTIAL | StreamManager.NormalizeConfig() | Deep copy via manual property assignment; similar intent | | StreamConsumerLimits | stream.go:163-166 | MISSING | — | Not ported | | SubjectTransformConfig | stream.go:169-172 | PARTIAL | StreamConfig.SubjectTransformSource/Dest | Flattened into StreamConfig instead of nested object | | RePublish | stream.go:175-179 | PARTIAL | StreamConfig.RePublishSource/Dest/HeadersOnly | Flattened into StreamConfig instead of nested object | | PersistModeType (enum) | stream.go:182-202 | PORTED | Models/StreamConfig.cs PersistMode | Sync=0, Async=1 | | PersistModeType.MarshalJSON/UnmarshalJSON | stream.go:215-236 | NOT_APPLICABLE | — | System.Text.Json handles it | | JSPubAckResponse | stream.go:239-242 | PARTIAL | Publish/PubAck.cs | Different structure; no wrapping ApiError | | PubAck | stream.go:255-263 | PARTIAL | Publish/PubAck.cs | Has Stream/Seq; missing Domain, Duplicate, Value, BatchId, BatchSize | | CounterValue | stream.go:267-269 | MISSING | — | Not ported | | CounterSources | stream.go:273 | MISSING | — | Not ported | | StreamInfo | stream.go:276-287 | PARTIAL | Api/JetStreamApiResponse.cs JetStreamStreamInfo | Has Config+State; missing Created, Domain, Cluster, Mirror, Sources, Alternates, TimeStamp | | ClusterInfo | stream.go:304-312 | MISSING | — | Not ported as standalone API type | | PeerInfo | stream.go:316-325 | MISSING | — | Not ported as standalone API type | | StreamSourceInfo | stream.go:328-336 | PARTIAL | MirrorSource/MirrorCoordinator.cs MirrorInfoResponse | Simplified; missing External, SubjectTransforms | | StreamSource (struct) | stream.go:339-349 | PARTIAL | Models/StreamConfig.cs StreamSourceConfig | Has Name, FilterSubject, SourceAccount; missing OptStartSeq, OptStartTime, SubjectTransforms, External, iname | | ExternalStream | stream.go:352-355 | MISSING | — | Not ported | | ExternalStream.Domain() | stream.go:358-363 | MISSING | — | Not ported | | stream ingest constants | stream.go:366-384 | MISSING | — | streamDefaultMaxQueueMsgs/Bytes, batch inflight constants not ported | | stream (struct, ~110 fields) | stream.go:388-497 | PARTIAL | StreamManager + StreamHandle | StreamHandle is simplified record; stream struct's ~110 fields reduced to Config+Store; no mu/client/sysc/msgs/gets/ackq/lseq/ddmap/mirror/sources/node/etc | | inflightSubjectRunningTotal | stream.go:500-503 | MISSING | — | Not ported | | msgCounterRunningTotal | stream.go:508-511 | MISSING | — | Not ported | | sourceInfo (struct) | stream.go:514-533 | PARTIAL | MirrorSource/SourceCoordinator.cs | Simplified source tracking | | JS header constants (JSMsgId, JSExpectedStream, etc.) | stream.go:543-598 | PARTIAL | Publish/PublishOptions.cs | Some headers used in publish path; no centralized header constant file | | KV operation headers | stream.go:571-573 | MISSING | — | Not ported | | Scheduler headers | stream.go:577-580 | MISSING | — | Not ported | | Republish response headers | stream.go:584-591 | MISSING | — | Not ported | | Rollup constants | stream.go:595-597 | MISSING | — | Not ported | | Delete marker reason constants | stream.go:601-604 | MISSING | — | Not ported | | ddentry (struct) | stream.go:612-616 | PARTIAL | Publish/PublishPreconditions.cs DedupeEntry | Has Sequence+Timestamp; id handled as dictionary key | | StreamMaxReplicas | stream.go:619 | MISSING | — | Not ported as constant | | addStream() / addStreamWithAssignment() | stream.go:621-980 | PARTIAL | StreamManager.CreateOrUpdate() | High-level create/update logic present; missing: account limits checking, inflight WaitGroup, file store config auto-tuning, cluster mode handling, internal client setup, pubAck template, dedupe rebuild, advisory sending | | StreamSource.composeIName() | stream.go:986-1022 | MISSING | — | Source indexing not ported | | StreamSource.setIndexName() | stream.go:1026-1027 | MISSING | — | Same | | stream.streamAssignment() | stream.go:1030-1033 | MISSING | — | Not ported (cluster-specific) | | stream.setStreamAssignment() | stream.go:1036-1078 | MISSING | — | Not ported (cluster-specific) | | stream.monitorQuitC() | stream.go:1081-1091 | MISSING | — | Not ported | | stream.signalMonitorQuit() | stream.go:1095-1102 | MISSING | — | Not ported | | stream.updateC() | stream.go:1105-1111 | MISSING | — | Not ported | | stream.IsLeader() / isLeader() | stream.go:1115-1126 | PARTIAL | JetStreamMetaGroup has leader concept | Not on stream level | | stream.setLeader() | stream.go:1142-1185 | MISSING | — | No stream-level leader management | | stream.startClusterSubs() / stopClusterSubs() | stream.go:1189-1200 | MISSING | — | Not ported | | stream.account() | stream.go:1203-1219 | MISSING | — | No per-stream account binding | | stream.maxMsgSize() | stream.go:1223-1253 | PARTIAL | StreamApiHandlers has MaxMsgSize validation | Not a stream method | | stream.autoTuneFileStorageBlockSize() | stream.go:1259-1288 | MISSING | — | No block size auto-tuning | | stream.rebuildDedupe() | stream.go:1296-1326 | PARTIAL | PublishPreconditions | Basic dedupe exists; no rebuild-from-store on recovery | | stream.lastSeqAndCLFS() | stream.go:1330-1331 | MISSING | — | Cluster failure sequence tracking not ported | | stream.getCLFS() / setCLFS() | stream.go:1334-1346 | MISSING | — | Same | | stream.lastSeq() / setLastSeq() | stream.go:1349-1358 | MISSING | — | StreamHandle doesn't track lseq | | stream.sendCreateAdvisory() | stream.go:1361-1390 | MISSING | — | Advisory publishing not ported at stream level | | stream.sendDeleteAdvisoryLocked() | stream.go:1393-1413 | MISSING | — | Same | | stream.sendUpdateAdvisoryLocked() | stream.go:1416-1436 | MISSING | — | Same | | stream.sendStreamBatchAbandonedAdvisory() | stream.go:1439-1464 | MISSING | — | Same | | stream.createdTime() / setCreatedTime() | stream.go:1468-1479 | MISSING | — | Not tracked on StreamHandle | | jsa.subjectsOverlap() | stream.go:1485-1498 | PORTED | StreamManager.ValidateConfigUpdate() | Subject overlap check exists in ValidateConfigUpdate | | checkStreamCfg() | stream.go:1500-2084 | PARTIAL | JetStreamConfigValidator.Validate() + StreamManager.CreateOrUpdate() | Basic name/subject/retention validation; many checks missing: MaxBytes limits, per-account limits, subject transform validation, republish cycle detection done separately, pedantic mode, placement validation | | jsa.configUpdateCheck() | stream.go:2104-2236 | PARTIAL | StreamManager.ValidateConfigUpdate() | Immutable fields checked: storage, retention, mirror, sources, maxConsumers, replicas; missing: sealed/denyDelete/denyPurge unset checks, TTL status, counter setting, schedules, persist mode, limit adjustment, compression | | stream.update() / updateWithAdvisory() | stream.go:2240-2554 | PARTIAL | StreamManager.CreateOrUpdate() | Config update path exists but much simplified; missing: subscription management, dedupe timer reset, source consumer management, direct/mirror-direct subscription toggling, republish transform update, subject transform update, tier usage tracking, advisory sending | | stream.purge() / purgeLocked() | stream.go:2567-2642 | PARTIAL | StreamManager.Purge() + PurgeEx() | Basic purge and extended purge present; missing: sealed check, consumer purge propagation, preAck clearing | | stream.deleteMsg() / removeMsg() | stream.go:2645-2663 | PARTIAL | StreamManager.DeleteMessage() | Basic removal present; missing: preAck clearing | | stream.eraseMsg() | stream.go:2666-2678 | PARTIAL | IStreamStore.EraseMsg on interface | Interface defined but no erase implementation that overwrites with random data | | stream.isMirror() | stream.go:2681-2685 | PORTED | StreamManager.GetMirrorInfo() checks mirror | Inline check | | stream.sourcesInfo() | stream.go:2688-2695 | PARTIAL | StreamManager.GetSourceInfos() | Simplified | | stream.sourceInfo() | stream.go:2699-2735 | PARTIAL | SourceCoordinator.GetSourceInfo() | Simplified | | stream.mirrorInfo() | stream.go:2739-2743 | PARTIAL | StreamManager.GetMirrorInfo() | Simplified | | stream.retryDisconnectedSyncConsumers() | stream.go:2747-2778 | MISSING | — | Not ported | | source health constants | stream.go:2782-2785 | MISSING | — | Not ported | | stream.processMirrorMsgs() | stream.go:2788-2854 | PARTIAL | MirrorCoordinator | Simplified mirror message processing; no health check, stall detection, flow control | | sourceInfo.isCurrentSub() | stream.go:2859-2860 | MISSING | — | Not ported | | stream.processInboundMirrorMsg() | stream.go:2863-3014 | PARTIAL | MirrorCoordinator.OnOriginAppendAsync() | Greatly simplified; no sequence tracking, flow control, heartbeat handling, skip logic | | stream.setMirrorErr() | stream.go:3017-3022 | MISSING | — | Not ported | | stream.cancelMirrorConsumer() | stream.go:3027-3032 | MISSING | — | Not ported | | stream.retryMirrorConsumer() | stream.go:3038-3044 | MISSING | — | Not ported | | stream.skipMsgs() | stream.go:3048-3073 | MISSING | — | No skip with NRG proposal | | calculateRetryBackoff() | stream.go:3084-3089 | MISSING | — | Not ported | | stream.scheduleSetupMirrorConsumerRetry() | stream.go:3098-3118 | MISSING | — | Not ported | | stream.setupMirrorConsumer() | stream.go:3125-3416 | MISSING | — | Full mirror consumer setup with API-based consumer creation, subject transforms, delivery tracking not ported | | stream.streamSource() | stream.go:3419-3424 | MISSING | — | Not ported | | stream.retrySourceConsumerAtSeq() | stream.go:3429-3435 | MISSING | — | Not ported | | stream.cancelSourceConsumer() | stream.go:3439-3443 | MISSING | — | Not ported | | stream.cancelSourceInfo() | stream.go:3451-3470 | MISSING | — | Not ported | | stream.setupSourceConsumer() | stream.go:3478-3500+ | MISSING | — | Full source consumer setup not ported (continues past line 4000) |

| Status | Count | | PORTED | 55 | | PARTIAL | 30 | | MISSING | 75 | | NOT_APPLICABLE | 12 | | DEFERRED | 0 | | Total | 172 |

| (si *sourceInfo) genSourceHeader | stream.go:4010 | MISSING | — | Generates 2.10-style source header (stream name, seq, filter, transform). No .NET equivalent; SourceCoordinator tracks seq differently. | | streamAndSeqFromAckReply | stream.go:4041 | MISSING | — | Parses stream/seq from $JS.ACK reply tokens. No wire-level reply parsing in .NET. | | streamAndSeq | stream.go:4058 | MISSING | — | Extracts stream name, index name, sequence from source header string. No .NET equivalent. | | (mset *stream) setStartingSequenceForSources | stream.go:4079 | PARTIAL | SourceCoordinator.LastOriginSequence | Go scans stored messages backwards to find starting seq per source using gsl.SimpleSublist. .NET SourceCoordinator has simpler resume-from-last logic. | | (mset *stream) resetSourceInfo | stream.go:4172 | PARTIAL | StreamManager.RebuildReplicationCoordinators | Go resets all sourceInfo structs with transforms. .NET rebuilds coordinators but lacks per-source subject transforms array. | | (mset *stream) startingSequenceForSources | stream.go:4207 | PARTIAL | SourceCoordinator.LastOriginSequence | Go does reverse scan with SimpleSublist filtering. .NET relies on simpler incremental tracking. |

| (mset *stream) setupSourceConsumers | stream.go:4318 | PARTIAL | SourceCoordinator.StartSyncLoop / StartPullSyncLoop | Go creates internal consumers per source with proper starting sequences. .NET has background sync loops but no internal consumer creation. | | (mset *stream) subscribeToStream | stream.go:4348 | MISSING | — | Creates internal subscriptions for all stream subjects + mirror/source setup. .NET uses StreamManager.Capture instead of subscription-based ingest. | | (mset *stream) subscribeToDirect | stream.go:4406 | PARTIAL | DirectApiHandlers.HandleGet | Go creates queue subscriptions for $JS.API.DIRECT.GET.{stream}. .NET has API handler but no queue-subscription wiring. | | (mset *stream) unsubscribeToDirect | stream.go:4431 | MISSING | — | Unsubscribes direct get subscriptions. No .NET equivalent. | | (mset *stream) subscribeToMirrorDirect | stream.go:4443 | MISSING | — | Sets up direct-get queue subs for mirror stream name. Not implemented in .NET. | | (mset *stream) unsubscribeToMirrorDirect | stream.go:4474 | MISSING | — | Clears mirror direct-get subscriptions. Not implemented. | | (mset *stream) stopSourceConsumers | stream.go:4487 | PORTED | SourceCoordinator.StopAsync | .NET coordinator has async stop with cancellation. | | (mset *stream) removeInternalConsumer | stream.go:4494 | MISSING | — | Clears consumer name on sourceInfo. .NET doesn't track internal consumer names. | | (mset *stream) unsubscribeToStream | stream.go:4503 | MISSING | — | Unsubscribes from all stream subjects, mirrors, sources. .NET uses StreamManager.Delete instead. | | (mset *stream) deleteInflightBatches | stream.go:4535 | PARTIAL | JetStreamPublisher.ClearBatches | Go cleans up batch state with lock ordering. .NET has simplified ClearBatches on AtomicBatchPublishEngine. | | (mset *stream) deleteBatchApplyState | stream.go:4552 | MISSING | — | Cleans up raft batch-apply entries with pool return. No .NET equivalent (no RAFT batch apply). |

| (mset *stream) subscribeInternal | stream.go:4563 | MISSING | — | Creates internal subscription with auto-incremented SID. .NET server doesn't use internal subscriptions for JetStream. | | (mset *stream) queueSubscribeInternal | stream.go:4577 | MISSING | — | Creates internal queue subscription. Not implemented in .NET. | | (mset *stream) unsubscribeInternal | stream.go:4594 | MISSING | — | Removes internal subscription by subject lookup. Not implemented. | | (mset *stream) unsubscribe | stream.go:4616 | MISSING | — | Unsubscribes by subscription pointer. Not implemented. |

| (mset *stream) setupStore | stream.go:4623 | PARTIAL | StreamManager.CreateStore | Go wires up MemStore/FileStore with encryption, callbacks for storage updates, remove msg, and process inbound. .NET creates store but lacks callback wiring. | | (mset *stream) storeUpdates | stream.go:4682 | MISSING | — | Callback for store changes: updates consumer pending counts, JetStream account usage. No .NET equivalent. |

| (mset *stream) numMsgIds | stream.go:4714 | MISSING | — | Returns count of tracked dedup entries. Not exposed in .NET. | | (mset *stream) checkMsgId | stream.go:4721 | PORTED | PublishPreconditions.IsDuplicate | .NET uses ConcurrentDictionary-based dedup check. | | (mset *stream) purgeMsgIds | stream.go:4731 | PORTED | PublishPreconditions.TrimOlderThan | Go uses timer-driven purge with GC compaction. .NET does cutoff-based trim. Lacks timer scheduling. | | (mset *stream) storeMsgId | stream.go:4778 | PORTED | PublishPreconditions.Record | .NET records msgId with timestamp. | | (mset *stream) storeMsgIdLocked | stream.go:4786 | PORTED | PublishPreconditions.Record | Internal locked variant; .NET uses ConcurrentDictionary. |

| getMsgId | stream.go:4803 | MISSING | — | Fast lookup of Nats-Msg-Id header from raw bytes. .NET uses PublishOptions.MsgId instead. | | getExpectedLastMsgId | stream.go:4808 | MISSING | — | Fast lookup of Nats-Expected-Last-Msg-Id. .NET checks via PublishOptions.ExpectedLastMsgId. | | getExpectedStream | stream.go:4813 | MISSING | — | Fast lookup of Nats-Expected-Stream. Not implemented as wire parser. | | getExpectedLastSeq | stream.go:4818 | MISSING | — | Fast lookup of Nats-Expected-Last-Sequence. .NET uses PublishOptions.ExpectedLastSeq. | | getRollup | stream.go:4827 | MISSING | — | Fast lookup of Nats-Rollup header. No rollup support in .NET. | | getExpectedLastSeqPerSubject | stream.go:4836 | MISSING | — | Fast lookup of Nats-Expected-Last-Subject-Sequence. .NET uses PublishOptions but no wire parser. | | getExpectedLastSeqPerSubjectForSubject | stream.go:4845 | MISSING | — | Subject override for per-subject seq check. Not in .NET. | | getMessageTTL | stream.go:4852 | MISSING | — | Parses Nats-Msg-TTL header from raw bytes. Not implemented in .NET. | | parseMessageTTL | stream.go:4863 | MISSING | — | Parses TTL string ("never", duration, seconds). Not implemented. | | getMessageIncr | stream.go:4888 | MISSING | — | Parses Nats-Msg-Incr header for counter streams. Not implemented. | | getMessageSchedule | stream.go:4898 | MISSING | — | Parses Nats-Msg-Schedule header. Not implemented. | | nextMessageSchedule | stream.go:4907 | MISSING | — | Calculates next schedule from header + timestamp. Not implemented. | | getMessageScheduleTTL | stream.go:4917 | MISSING | — | Parses schedule TTL header. Not implemented. | | getMessageScheduleTarget | stream.go:4930 | MISSING | — | Parses schedule target header. Not implemented. | | getMessageScheduleSource | stream.go:4938 | MISSING | — | Parses schedule source header. Not implemented. | | getMessageScheduler | stream.go:4946 | MISSING | — | Parses scheduler header. Not implemented. | | getBatchId | stream.go:4954 | MISSING | — | Parses Nats-Batch-Id header from raw bytes. .NET uses PublishOptions.BatchId instead. | | getBatchSequence | stream.go:4962 | MISSING | — | Parses Nats-Batch-Seq header. .NET uses PublishOptions.BatchSeq. |

| (mset *stream) IsClustered | stream.go:4971 | NOT_APPLICABLE | — | Checks if RAFT node is present. .NET uses JetStreamMetaGroup for cluster simulation but not per-stream RAFT. | | (mset *stream) isClustered | stream.go:4978 | NOT_APPLICABLE | — | Lock-held variant. |

| inMsg struct | stream.go:4983 | MISSING | — | Internal message queue struct (subj, reply, hdr, msg, sourceInfo, msgTrace). .NET doesn't have internal msg queue. | | inMsgPool | stream.go:4994 | MISSING | — | sync.Pool for inMsg objects. Not needed without internal queue. | | (im *inMsg) returnToPool | stream.go:4999 | MISSING | — | Returns inMsg to pool. | | (mset *stream) queueInbound | stream.go:5004 | MISSING | — | Enqueues inbound message with rate limit error on overflow. .NET uses direct method calls instead. |

| dgPool / directGetReq | stream.go:5019 | MISSING | — | Pool and struct for deferred direct get requests. | | (mset *stream) processDirectGetRequest | stream.go:5033 | PARTIAL | DirectApiHandlers.HandleGet | Go handles full JSApiMsgGetRequest with validation. .NET only supports seq-based lookup. Missing: LastFor, NextFor, MultiLastFor, StartTime, Batch, MaxBytes. | | (mset *stream) processDirectGetLastBySubjectRequest | stream.go:5087 | MISSING | — | Direct get by subject appended to request subject. Not implemented in .NET. | | (mset *stream) getDirectMulti | stream.go:5158 | MISSING | — | Multi-subject direct get with batch response + EOB. Not implemented. | | (mset *stream) getDirectRequest | stream.go:5270 | PARTIAL | DirectApiHandlers.HandleGet | Go handles seq, NextFor, LastFor, batch, MaxBytes, NoHeaders. .NET only handles seq lookup. | | Direct get header constants (dg, dgb, eob, eobm) | stream.go:5150 | MISSING | — | Wire format header templates for direct get responses. |

| (mset *stream) processInboundJetStreamMsg | stream.go:5409 | MISSING | — | Entry point: copies msg, adds trace, queues inbound. .NET uses StreamManager.Capture. | | Error sentinel variables | stream.go:5428 | PARTIAL | — | errLastSeqMismatch, errMsgIdDuplicate, etc. .NET uses error codes in PubAck instead. | | (mset *stream) processJetStreamMsg | stream.go:5437 | PARTIAL | JetStreamPublisher.TryCaptureWithOptions + StreamManager.Capture | Core message processing. Go: full consistency checks, subject transform, sealed/sealed check, header extraction, dedup, TTL, counter increment, schedule validation, rollup, interest retention skip, store. .NET: basic dedup + expected-last-seq + capture. Missing: rollup, TTL, counters, schedules, per-subject seq, interest retention skip, sealed check at msg level, clustered RAFT propose. |

| jsPubMsg struct | stream.go:6770 | MISSING | — | Internal pub message with dest subject, reply, store msg, consumer ref. | | newJSPubMsg | stream.go:6786 | MISSING | — | Constructor with pool allocation. | | jsPubMsgPool | stream.go:6784 | MISSING | — | sync.Pool for jsPubMsg. | | (pm *jsPubMsg) returnToPool | stream.go:6815 | MISSING | — | Pool return. | | (pm *jsPubMsg) size | stream.go:6826 | MISSING | — | Size calculation for flow control. | | jsOutQ struct | stream.go:6834 | MISSING | — | Typed output queue wrapper around ipQueue. | | (q *jsOutQ) sendMsg | stream.go:6838 | MISSING | — | Sends message on output queue. | | (q *jsOutQ) send | stream.go:6844 | MISSING | — | Pushes jsPubMsg to queue. | | StoredMsg struct | stream.go:6858 | PORTED | StoredMessage | .NET StoredMessage record has Subject, Sequence, Payload, TimestampUtc. | | (mset *stream) setupSendCapabilities | stream.go:6869 | MISSING | — | Creates output queue and launches internalLoop goroutine. | | (mset *stream) accName | stream.go:6881 | NOT_APPLICABLE | — | Returns account name. .NET uses Account directly. | | (mset *stream) name / nameLocked | stream.go:6892 | NOT_APPLICABLE | — | Returns stream name. .NET uses StreamHandle.Config.Name. | | (mset *stream) internalLoop | stream.go:6907 | MISSING | — | Main event loop: outq dispatch, inbound msg processing, direct gets, ack queue for interest retention. Complex select{} loop. Not implemented in .NET. |

| (mset *stream) resetAndWaitOnConsumers | stream.go:7037 | MISSING | — | Steps down and waits for consumer monitor goroutines. | | (mset *stream) delete | stream.go:7059 | PARTIAL | StreamManager.Delete | Go calls stop(true, true) with advisory. .NET removes from ConcurrentDictionary. | | (mset *stream) stop | stream.go:7067 | PARTIAL | StreamManager.Delete | Go: full shutdown sequence (mark closed, signal monitor, unsubscribe, cleanup consumers, advisories, RAFT node stop/delete, dedup timer cleanup, queue unregister, store delete/stop). .NET: simple dictionary removal. |

| (mset *stream) getMsg | stream.go:7249 | PORTED | StreamManager.GetMessage | .NET loads from store by sequence. | | (mset *stream) getConsumers | stream.go:7266 | PARTIAL | ConsumerManager | Go returns copy of consumer list. .NET has ConsumerManager but not per-stream consumer list. | | (mset *stream) numPublicConsumers | stream.go:7273 | MISSING | — | Count of non-DIRECT consumers. Not in .NET. | | (mset *stream) getPublicConsumers | stream.go:7278 | MISSING | — | Filters out DIRECT consumers. Not in .NET. | | (mset *stream) getDirectConsumers | stream.go:7292 | MISSING | — | Returns only DIRECT consumers. Not in .NET. | | (mset *stream) numDirectConsumers | stream.go:7471 | MISSING | — | Counts DIRECT consumers. Not in .NET. | | (mset *stream) state | stream.go:7487 | PORTED | StreamManager.GetStateAsync | .NET delegates to store.GetStateAsync. | | (mset *stream) stateWithDetail | stream.go:7490 | PARTIAL | StreamManager.GetStateAsync | Go has fast path (FastState) vs detailed (State). .NET always returns full state. | | (mset *stream) Store | stream.go:7509 | PORTED | StreamHandle.Store | Direct property access in .NET record. |

| (mset *stream) setConsumer | stream.go:7367 | MISSING | — | Registers consumer on stream with filter tracking and consumer sublist (gsl). .NET uses separate ConsumerManager. | | (mset *stream) removeConsumer | stream.go:7388 | MISSING | — | Removes consumer from stream's maps and sublists. .NET uses ConsumerManager. | | (mset *stream) swapSigSubs | stream.go:7416 | MISSING | — | Updates signal subscriptions when consumer filter changes. Complex lock ordering. Not in .NET. | | (mset *stream) lookupConsumer | stream.go:7464 | PARTIAL | ConsumerManager | Go looks up by name on stream. .NET uses separate manager. | | (mset *stream) partitionUnique | stream.go:7516 | MISSING | — | Checks consumer filter partitions don't overlap. Not implemented. | | (mset *stream) potentialFilteredConsumers | stream.go:7541 | MISSING | — | Checks if filtered consumer matching is needed. Not in .NET. |

| checkInterestStateT/J constants | stream.go:7307 | MISSING | — | Timer interval/jitter for interest state checks. | | (mset *stream) checkInterestState | stream.go:7320 | PARTIAL | InterestRetentionPolicy.ShouldRetain | Go checks ack floors across all consumers and compacts. .NET has simpler per-seq interest check. | | (mset *stream) isInterestRetention | stream.go:7353 | PORTED | Config check | .NET checks stream.Config.Retention == RetentionPolicy.Interest. | | (mset *stream) numConsumers | stream.go:7360 | PARTIAL | ConsumerManager | Go returns from stream's consumer map. .NET has ConsumerManager. | | (mset *stream) noInterest | stream.go:7556 | PARTIAL | InterestRetentionPolicy.ShouldRetain | .NET has simplified interest check without pre-ack support. | | (mset *stream) noInterestWithSubject | stream.go:7562 | PARTIAL | InterestRetentionPolicy.ShouldRetain | .NET uses SubjectMatch filtering. | | (mset *stream) checkForInterest | stream.go:7567 | PARTIAL | InterestRetentionPolicy.ShouldRetain | Go loads message for subject, checks filtered consumers. .NET simpler. | | (mset *stream) checkForInterestWithSubject | stream.go:7588 | PARTIAL | InterestRetentionPolicy.ShouldRetain | Go iterates consumers with needAck check. .NET iterates registered interests. | | (mset *stream) hasPreAck | stream.go:7605 | MISSING | — | Pre-ack tracking for messages acked before stored. Not in .NET. | | (mset *stream) hasAllPreAcks | stream.go:7619 | MISSING | — | Checks if all consumers pre-acked a sequence. Not in .NET. | | (mset *stream) clearAllPreAcks | stream.go:7631 | MISSING | — | Clears pre-ack map for a sequence. Not in .NET. | | (mset *stream) clearAllPreAcksBelowFloor | stream.go:7636 | MISSING | — | Clears pre-acks below a floor sequence. Not in .NET. | | (mset *stream) registerPreAckLock | stream.go:7645 | MISSING | — | Lock-acquiring pre-ack registration. Not in .NET. | | (mset *stream) registerPreAck | stream.go:7654 | MISSING | — | Registers pre-ack for consumer/sequence. Not in .NET. | | (mset *stream) clearPreAck | stream.go:7669 | MISSING | — | Clears single consumer pre-ack. Not in .NET. | | (mset *stream) ackMsg | stream.go:7685 | PARTIAL | InterestRetentionPolicy + AckProcessor | Go: full ack processing with pre-ack, clustered proposal, interest-raise-first. .NET has basic interest check + removal. |

| (mset *stream) snapshot | stream.go:7764 | PORTED | StreamSnapshotService.CreateTarSnapshotAsync | .NET uses TAR+S2 snapshot service. | | (a *Account) RestoreStream | stream.go:7776 | PARTIAL | StreamSnapshotService.RestoreTarSnapshotAsync | Go: full restore with config validation, limit checks, directory management, consumer restore. .NET: simplified restore (purge + replay). Missing: config validation, consumer restore, limit checks. |

| (mset *stream) checkForOrphanMsgs | stream.go:7979 | MISSING | — | Checks for dangling messages on interest retention streams at startup. Not implemented. |

| (mset *stream) checkConsumerReplication | stream.go:8007 | MISSING | — | Verifies consumer replication matches stream for interest retention. Not in .NET. | | (mset *stream) checkInMonitor | stream.go:8029 | NOT_APPLICABLE | — | Atomic flag for monitor goroutine. .NET has no stream monitor loop. | | (mset *stream) clearMonitorRunning | stream.go:8041 | NOT_APPLICABLE | — | Clears monitor flag + cleanup. | | (mset *stream) isMonitorRunning | stream.go:8051 | NOT_APPLICABLE | — | Checks monitor flag. | | (mset *stream) trackReplicationTraffic | stream.go:8058 | NOT_APPLICABLE | — | Adjusts account stats for replication. .NET has no account-level replication stats. |

| Status | Count | | PORTED | 11 | | PARTIAL | 24 | | MISSING | 73 | | NOT_APPLICABLE | 8 | | DEFERRED | 0 | | Total | 116 |

| ConsumerInfo | consumer.go:55 | PARTIAL | JetStreamConsumerInfo (Api/JetStreamApiResponse.cs) | .NET has a simplified version inside API response; missing most fields (Delivered, AckFloor, NumAckPending, NumRedelivered, NumWaiting, NumPending, Cluster, PushBound, Paused, PauseRemaining, TimeStamp, PriorityGroups) | | consumerInfoClusterResponse | consumer.go:77 | MISSING | — | Cluster-internal response type for consumer info propagation | | PriorityGroupState | consumer.go:82 | MISSING | — | Reported in ConsumerInfo; no equivalent struct | | ConsumerConfig | consumer.go:88 | PORTED | ConsumerConfig (Models/ConsumerConfig.cs) | All major fields present. Minor: missing Description, SampleFrequency, Replicas, MemoryStorage, Direct, InactiveThreshold, HeadersOnly, Name (vs Durable), DeliverGroup | | SequenceInfo | consumer.go:143 | MISSING | — | Used in ConsumerInfo; no standalone equivalent | | CreateConsumerRequest | consumer.go:149 | PARTIAL | Parsed inline in ConsumerApiHandlers.ParseConfig | Missing Action and Pedantic fields | | ConsumerAction enum | consumer.go:156 | MISSING | — | ActionCreateOrUpdate/ActionUpdate/ActionCreate not modeled | | ConsumerAction.MarshalJSON/UnmarshalJSON | consumer.go:188-213 | MISSING | — | JSON serialization for consumer actions | | ConsumerNakOptions | consumer.go:216 | PARTIAL | Parsed inline in AckProcessor.ProcessAck | Delay extraction exists but not as a typed struct | | PriorityPolicy enum | consumer.go:221 | PORTED | PriorityPolicy (Models/ConsumerConfig.cs:80) | Has None, Overflow, PinnedClient. Missing Prioritized variant | | PriorityPolicy.MarshalJSON/UnmarshalJSON | consumer.go:261-290 | NOT_APPLICABLE | — | .NET uses enum serialization | | DeliverPolicy enum | consumer.go:293 | PORTED | DeliverPolicy (Models/JetStreamPolicies.cs:16) | All 6 variants present | | AckPolicy enum | consumer.go:330 | PORTED | AckPolicy (Models/ConsumerConfig.cs:69) | All 3 variants present | | ReplayPolicy enum | consumer.go:354 | PORTED | ReplayPolicy (Models/JetStreamPolicies.cs:27) | Both variants present |

| AckAck/AckOK/AckNak/AckProgress/AckNext/AckTerm | consumer.go:376-388 | PORTED | AckType enum + AckProcessor.ParseAckType (Consumers/AckProcessor.cs:127) | All ack types recognized; AckNext (+NXT) handled implicitly | | ackTermLimitsReason/ackTermUnackedLimitsReason | consumer.go:391-394 | MISSING | — | Reason strings for limit-based terminations | | JSPullRequestPendingMsgs/Bytes/NatsPinId | consumer.go:43-46 | PARTIAL | Used in heartbeat headers in PushConsumerEngine | PinId header not used | | JsPullRequestRemainingBytesT | consumer.go:53 | MISSING | — | Template for 409 Batch Completed response | | validGroupName regex | consumer.go:49 | MISSING | — | Group name validation regex ^[a-zA-Z0-9/_=-]{1,16}$ |

| consumer struct | consumer.go:409 | PARTIAL | ConsumerHandle (ConsumerManager.cs:331) | ConsumerHandle is a simplified record with NextSequence, Paused, PauseUntilUtc, Pending, PushFrames, AckProcessor. Missing: most of the ~80 fields (leader, client, sysc, sid, sseq, dseq, adflr, asflr, subjf, filters, dsubj, qgroup, lss, rlimit, ackSub, reqSub, etc.) | | subjectFilter struct | consumer.go:529 | PORTED | CompiledFilter (Consumers/PullConsumerEngine.cs:15) | Different approach but equivalent functionality | | subjectFilters type | consumer.go:535 | PORTED | CompiledFilter.FromConfig | Encapsulated in CompiledFilter | | proposal struct | consumer.go:547 | MISSING | — | RAFT proposal linked list for clustered consumers |

| JsAckWaitDefault (30s) | consumer.go:554 | PORTED | ConsumerConfig.AckWaitMs = 30_000 | Default set in ConsumerConfig | | JsDeleteWaitTimeDefault (5s) | consumer.go:557 | PARTIAL | DeliveryInterestTracker(TimeSpan.FromSeconds(30)) | Different default (30s vs 5s) | | JsFlowControlMaxPending (32MB) | consumer.go:559 | PARTIAL | MaxFlowControlPending = 2 (frames, not bytes) | Different unit/approach | | JsDefaultMaxAckPending (1000) | consumer.go:561 | MISSING | — | Not applied as default in ConsumerConfig | | JsDefaultPinnedTTL (2min) | consumer.go:564 | MISSING | — | Not applied as default |

| setConsumerConfigDefaults | consumer.go:568 | MISSING | — | 110-line function setting MaxDeliver=-1, MaxWaiting defaults, AckWait defaults, BackOff override, MaxAckPending defaults, MaxRequestBatch limits, PinnedTTL default. No .NET equivalent | | checkConsumerCfg | consumer.go:680 | MISSING | — | 270-line comprehensive validation function. No .NET equivalent (JetStreamConfigValidator only validates streams) | | ConsumerConfig.replicas | consumer.go:397 | MISSING | — | Replicas calculation against parent stream | | deliveryFormsCycle | referenced at consumer.go:743 | MISSING | — | Cycle detection for push delivery subjects |

| stream.addConsumer | consumer.go:956 | PARTIAL | ConsumerManager.CreateOrUpdate | Simplified: no WorkQueue checks, no replica validation, no RAFT, no event subjects | | stream.addConsumerWithAction | consumer.go:952 | PARTIAL | ConsumerManager.CreateOrUpdate | Action parameter not used | | stream.addConsumerWithAssignment | consumer.go:960 | PARTIAL | ConsumerManager.CreateOrUpdate | 370-line function. .NET has ~30 lines. Missing: durable update detection, WorkQueue partition uniqueness, consumer limit checks, store creation, ack subscription setup, subject filter compilation, stored state restoration, cluster assignment, rate limit setup, advisory sending | | consumer.updateInactiveThreshold | consumer.go:1335 | MISSING | — | Jitter calculation for ephemeral delete timers | | consumer.updatePauseState | consumer.go:1358 | PARTIAL | ConsumerManager.Pause(stream, durable, DateTime) | Timer-based resume exists but simpler implementation |

| consumer.consumerAssignment | consumer.go:1383 | MISSING | — | No RAFT consumer assignment tracking | | consumer.setConsumerAssignment | consumer.go:1389 | MISSING | — | | | consumer.monitorQuitC | consumer.go:1407 | MISSING | — | Monitor goroutine quit channel | | consumer.signalMonitorQuit | consumer.go:1422 | MISSING | — | | | consumer.updateC | consumer.go:1431 | MISSING | — | | | consumer.checkQueueInterest | consumer.go:1439 | MISSING | — | Queue group interest checking | | consumer.clearNode | consumer.go:1459 | MISSING | — | RAFT node cleanup | | consumer.IsLeader/isLeader | consumer.go:1469 | MISSING | — | No leader election concept | | consumer.setLeader | consumer.go:1478 | MISSING | — | 240-line leader transition handling (subscribe internal ack/req/reset subs, flow control, push mode interest, delete timer, pause state, replay mode, start goroutines). Entirely missing |

| consumer.subscribeInternal | consumer.go:1723 | MISSING | — | Internal subscription for ack/request subjects | | consumer.unsubscribe | consumer.go:1743 | MISSING | — | | | consumer.handleClusterConsumerInfoRequest | consumer.go:1718 | MISSING | — | Cluster info request handler |

| consumer.sendAdvisory | consumer.go:1752 | MISSING | — | Generic advisory sender with interest check | | consumer.sendDeleteAdvisoryLocked | consumer.go:1771 | MISSING | — | Delete advisory | | consumer.sendPinnedAdvisoryLocked | consumer.go:1788 | MISSING | — | Pinned consumer advisory | | consumer.sendUnpinnedAdvisoryLocked | consumer.go:1807 | MISSING | — | Unpinned consumer advisory | | consumer.sendCreateAdvisory | consumer.go:1827 | MISSING | — | Create advisory | | consumer.sendPauseAdvisoryLocked | consumer.go:1847 | MISSING | — | Pause/unpause advisory |

| consumer.hasDeliveryInterest | consumer.go:1886 | PARTIAL | DeliveryInterestTracker (Consumers/DeliveryInterestTracker.cs) | .NET tracks subscriber count; Go checks sublist + gateway interest | | Server.hasGatewayInterest | consumer.go:1908 | MISSING | — | Gateway interest checking | | consumer.updateDeliveryInterest | consumer.go:1925 | PARTIAL | DeliveryInterestTracker.OnSubscribe/OnUnsubscribe | Simplified; no delete timer or queue group handling | | consumer.deleteNotActive | consumer.go:1977 | PARTIAL | DeliveryInterestTracker.ShouldDelete | Go has 160-line function with pull-mode elapsed checking, pending ack consideration, clustered delete proposal with retry. .NET is a simple boolean property | | consumer.watchGWinterest | consumer.go:2141 | MISSING | — | Gateway interest polling timer |

| Account.checkNewConsumerConfig | consumer.go:2274 | MISSING | — | 55-line validation of which config fields can be updated | | consumer.updateConfig | consumer.go:2333 | MISSING | — | 145-line config update handler (DeliverSubject, MaxAckPending, AckWait, RateLimit, SampleFrequency, MaxDeliver, InactiveThreshold, PauseUntil, FilterSubjects). Not ported | | consumer.updateDeliverSubject | consumer.go:2480 | MISSING | — | Push consumer delivery subject change | | consumer.updateDeliverSubjectLocked | consumer.go:2489 | MISSING | — | | | configsEqualSansDelivery | consumer.go:2506 | MISSING | — | Config comparison ignoring delivery subject |

| jsAckMsg struct | consumer.go:2519 | MISSING | — | Ack message struct with pooling | | jsAckMsgPool | consumer.go:2526 | MISSING | — | sync.Pool for ack messages | | consumer.pushAck | consumer.go:2552 | MISSING | — | Wire handler that pushes to ackMsgs queue | | consumer.processAck | consumer.go:2558 | PORTED | AckProcessor.ProcessAck(ulong, ReadOnlySpan<byte>) | All ack types dispatched (+ACK, -NAK, +TERM, +WPI, +NXT). Missing: ackReplyInfo parsing from subject, ack reply handling | | consumer.progressUpdate | consumer.go:2604 | PORTED | AckProcessor.ProcessProgress | Resets deadline | | consumer.updateSkipped | consumer.go:2616 | MISSING | — | RAFT proposal for skip | | consumer.resetStartingSeq | consumer.go:2628 | PARTIAL | ConsumerManager.ResetToSequence | Simplified; missing deliver policy validation, RAFT proposal, interest stream cleanup | | consumer.resetLocalStartingSeq | consumer.go:2691 | PARTIAL | ConsumerManager.ResetToSequence | Clears pending and resets sequence |

| consumer.loopAndForwardProposals | consumer.go:2700 | MISSING | — | RAFT proposal forwarding goroutine | | consumer.propose | consumer.go:2761 | MISSING | — | Add to proposal linked list | | consumer.updateDelivered | consumer.go:2778 | MISSING | — | RAFT-aware delivery tracking (proposes or stores locally) | | consumer.addAckReply | consumer.go:2799 | MISSING | — | Pending ack reply tracking for replicated consumers | | consumer.addReplicatedQueuedMsg | consumer.go:2808 | MISSING | — | Pending delivery tracking for replicated consumers | | consumer.updateAcks | consumer.go:2829 | MISSING | — | RAFT-aware ack update (proposes or stores locally) | | consumer.addClusterPendingRequest | consumer.go:2854 | PARTIAL | PullConsumerEngine.ProposeWaitingRequest | Simplified cluster pending tracking | | consumer.removeClusterPendingRequest | consumer.go:2866 | PARTIAL | PullConsumerEngine.RemoveClusterPending | | | consumer.setPendingRequestsOk | consumer.go:2877 | MISSING | — | Version-gated pending request support | | consumer.checkAndSetPendingRequestsOk | consumer.go:2890 | MISSING | — | Peer version checking | | consumer.checkPendingRequests | consumer.go:2915 | MISSING | — | Leadership change pending request notification | | consumer.releaseAnyPendingRequests | consumer.go:2931 | MISSING | — | Release waiting requests on delete/stop |

| consumer.processNak | consumer.go:2950 | PORTED | AckProcessor.ProcessNak | Delay extraction, backoff, redelivery queue. Missing: NAK advisory sending, JSON delay parsing (ConsumerNakOptions), duration string parsing | | consumer.processTerm | consumer.go:3030 | PORTED | AckProcessor.ProcessTerm | Removes from pending. Missing: TERM advisory, reason extraction |

| ackWaitDelay constant | consumer.go:3060 | MISSING | — | 1ms delay added to ack wait timer | | consumer.ackWait | consumer.go:3063 | MISSING | — | AckWait + delay calculation | | consumer.checkRedelivered | consumer.go:3072 | MISSING | — | Sanity check for rdc below ack floor | | consumer.readStoredState | consumer.go:3091 | MISSING | — | Restore state from store | | consumer.applyState | consumer.go:3107 | MISSING | — | Apply ConsumerState to consumer fields | | consumer.setStoreState | consumer.go:3135 | MISSING | — | Set state from snapshot restore | | consumer.writeStoreState/Unlocked | consumer.go:3147-3172 | MISSING | — | Persist state to store |

| consumer.initialInfo | consumer.go:3176 | MISSING | — | One-shot initial info | | consumer.clearInitialInfo | consumer.go:3189 | MISSING | — | | | consumer.info | consumer.go:3196 | PARTIAL | ConsumerManager.GetInfo | .NET returns only config; Go returns full ConsumerInfo with delivery/ack state, pending counts, waiting count, cluster info, priority groups | | consumer.infoWithSnap | consumer.go:3200 | MISSING | — | | | consumer.infoWithSnapAndReply | consumer.go:3204 | MISSING | — | 120-line info builder with store state, cluster info |

| consumer.signalNewMessages | consumer.go:3330 | PORTED | PushConsumerEngine.Signal(ConsumerSignal.NewMessage) | Channel-based signaling | | consumer.shouldSample | consumer.go:3339 | PORTED | SampleTracker.ShouldSample (Consumers/SampleTracker.cs) | Stochastic sampling | | consumer.sampleAck | consumer.go:3352 | PARTIAL | SampleTracker.RecordLatency | Records sample but does not send advisory | | consumer.processAckMsg | consumer.go:3382 | PARTIAL | AckProcessor.AckSequence / AckProcessor.AckAll | Core ack processing for Explicit/All/None policies. Missing: sample sending, cluster replication, retention policy notification, floor advancement algorithm differs |

| consumer.hasMaxDeliveries | consumer.go:2172 | PORTED | AckProcessor.ScheduleRedelivery (max deliver check) | Checks and handles exceeded sequences | | consumer.forceExpirePending | consumer.go:2203 | MISSING | — | Force all pending to redeliver queue | | consumer.deliveryCount | referenced | MISSING | — | Per-sequence delivery count lookup | | consumer.notifyDeliveryExceeded | referenced at 2180 | MISSING | — | Max delivery exceeded advisory |

| consumer.setRateLimit | consumer.go:2246 | PORTED | TokenBucketRateLimiter (Consumers/TokenBucketRateLimiter.cs) | Token bucket rate limiter. Go uses golang.org/x/time/rate; .NET has custom impl | | consumer.setRateLimitNeedsLocks | consumer.go:2228 | MISSING | — | Lock-safe rate limit update |

| ConsumerState struct (store.go) | referenced | PORTED | ConsumerState (Storage/ConsumerState.cs) | All fields: Delivered, AckFloor, Pending, Redelivered | | SequencePair struct (store.go) | referenced | PORTED | SequencePair (Storage/ConsumerState.cs:8) | | | Pending struct (store.go) | referenced | PORTED | Pending (Storage/ConsumerState.cs:17) | | | ConsumerStore interface | referenced | PORTED | IConsumerStore (Storage/IConsumerStore.cs) | All methods: SetStarting, UpdateStarting, Reset, HasState, UpdateDelivered, UpdateAcks, Update, State, BorrowState, EncodedState, Type, Stop, Delete, StreamDelete | | consumerFileStore | referenced | PORTED | ConsumerFileStore (Storage/ConsumerFileStore.cs) | File-backed store with background flusher | | encodeConsumerState/decodeConsumerState | referenced | PORTED | ConsumerStateCodec (Storage/ConsumerStateCodec.cs) | Go-compatible binary codec with varint encoding |

| Status | Count | | PORTED | 23 | | PARTIAL | 21 | | MISSING | 70 | | NOT_APPLICABLE | 1 | | Total | 115 |

| consumer.isFiltered() | consumer.go:3524 | PARTIAL | CompiledFilter in PullConsumerEngine.cs | .NET has CompiledFilter but lacks stream-subject comparison logic (checks subjf vs mset.cfg.Subjects) | | consumer.needAck() | consumer.go:3571 | PARTIAL | InterestRetentionPolicy.ShouldRetain() | .NET covers interest retention case but missing full ack-policy switch (AckNone/AckAll/AckExplicit), filtered match, and leader/follower state borrow | | consumer.isFilteredMatch() | consumer.go:4490 | PORTED | FilterSkipTracker.ShouldDeliver(), CompiledFilter.Matches() | Both use SubjectMatch for token-based matching; Go has tokenized optimization | | consumer.isEqualOrSubsetMatch() | consumer.go:4515 | MISSING | — | Checks if filter subject is equal to or subset of consumer's filter subjects; used in config validation |

| PriorityGroup (struct) | consumer.go:3635 | PORTED | PriorityGroupManager + PullWaitingRequest.Priority | Go struct fields (Group, MinPending, MinAckPending, Id, Priority) mapped across .NET types | | consumer.setPinnedTimer() | consumer.go:4000 | PARTIAL | PriorityGroupManager.AssignPinId() | .NET assigns pin ID but lacks TTL timer + unpinned advisory on timeout | | consumer.assignNewPinId() | consumer.go:4020 | PARTIAL | PriorityGroupManager.AssignPinId() | .NET assigns but missing pinnedTS tracking and pinned advisory send | | consumer.unassignPinId() | consumer.go:4032 | PORTED | PriorityGroupManager.UnassignPinId() | Timer stop + pin clear |

| waitingRequest (struct) | consumer.go:3690 | PORTED | PullWaitingRequest + PullRequest | Represented as records; Go has linked list pointers, .NET uses separate queue | | waitingDelivery (struct) | consumer.go:3731 | MISSING | — | Tracks pending replicated deliveries (seq, pending msgs/bytes); needed for clustered pull consumers | | waitQueue (struct) | consumer.go:3753 | PORTED | PullRequestWaitQueue + WaitingRequestQueue | Two .NET implementations: priority-based and FIFO | | newWaitQueue() | consumer.go:3761 | PORTED | PullRequestWaitQueue constructor | | | waitQueue.insertSorted() | consumer.go:3771 | PORTED | PullRequestWaitQueue.Enqueue() | Stable priority insertion sort | | waitQueue.addPrioritized() | consumer.go:3783 | PORTED | PullRequestWaitQueue.Enqueue() | | | waitQueue.add() | consumer.go:3798 | PORTED | WaitingRequestQueue.Enqueue() | FIFO append | | waitQueue.isFull() | consumer.go:3821 | PORTED | PullRequestWaitQueue max size check | | | waitQueue.isEmpty() | consumer.go:3828 | PORTED | WaitingRequestQueue.IsEmpty | | | waitQueue.len() | consumer.go:3835 | PORTED | WaitingRequestQueue.Count | | | waitQueue.peek() | consumer.go:3843 | PORTED | PullRequestWaitQueue.Peek() | | | waitQueue.cycle() | consumer.go:3850 | MISSING | — | Removes head and re-adds to tail; used for round-robin cycling | | waitQueue.popOrPopAndRequeue() | consumer.go:3860 | PORTED | PullRequestWaitQueue.PopAndRequeue() | Dispatches based on priority policy | | waitQueue.pop() | consumer.go:3873 | PORTED | PullRequestWaitQueue.Dequeue() | | | waitQueue.popAndRequeue() | consumer.go:3892 | PORTED | PullRequestWaitQueue.PopAndRequeue() | | | insertAtPosition() | consumer.go:3925 | PORTED | (inline in PullRequestWaitQueue.Enqueue) | Priority insertion logic | | waitQueue.removeCurrent() | consumer.go:3959 | PORTED | (implicit in Dequeue) | | | waitQueue.remove() | consumer.go:3964 | PARTIAL | — | Go supports arbitrary removal from linked list; .NET queue doesn't have arbitrary mid-list removal | | consumer.pendingRequests() | consumer.go:3988 | PARTIAL | PullConsumerEngine.GetClusterPendingRequests() | Returns pending as reply-keyed map vs collection | | consumer.nextWaiting() | consumer.go:4044 | PARTIAL | PullRequestWaitQueue.PopAndRequeue() | .NET has basic pop; Go has full priority pin-check logic, max-bytes rejection, expiry, interest checking |

| nextReqFromMsg() | consumer.go:3652 | PARTIAL | PullFetchRequest parsing in ConsumerApiHandlers | .NET parses batch from JSON; Go parses batch, maxBytes, noWait, expires, heartbeat, priorityGroup | | nextMsgReq (struct) | consumer.go:4186 | NOT_APPLICABLE | — | Pool-based message wrapper; .NET uses different request pipeline | | consumer.processNextMsgReq() | consumer.go:4219 | PARTIAL | ConsumerApiHandlers.HandleNext() | .NET has basic batch fetch; Go validates push vs pull, API level, and queues to ipQueue | | consumer.processNextMsgRequest() | consumer.go:4276 | PARTIAL | PullConsumerEngine.FetchAsync() | .NET handles basic fetch; Go handles maxRequestBatch/Expires/MaxBytes limits, priority group validation, noWait, interest tracking, queue add | | consumer.processResetReq() | consumer.go:4241 | PORTED | ConsumerManager.ResetToSequence() + ConsumerApiHandlers.HandleReset() | API handler + manager reset | | trackDownAccountAndInterest() | consumer.go:4419 | NOT_APPLICABLE | — | Account export response tracking for cross-account pull requests; not yet needed in .NET |

| consumer.deliveryCount() | consumer.go:4439 | PORTED | RedeliveryTracker._deliveryCounts access | Via dictionary lookup | | consumer.incDeliveryCount() | consumer.go:4452 | PORTED | RedeliveryTracker.IncrementDeliveryCount() | | | consumer.decDeliveryCount() | consumer.go:4463 | MISSING | — | Adjusts delivery count down on failed delivery; not present in .NET tracker | | consumer.notifyDeliveryExceeded() | consumer.go:4471 | PARTIAL | AckProcessor.ExceededSequences + DeliveryExceededPolicy | .NET tracks exceeded sequences; Go sends advisory event via sendAdvisory |

| consumer.getNextMsg() | consumer.go:4540 | PARTIAL | PullConsumerEngine.FetchAsync() | .NET handles basic store load + filter match; Go has full redelivery queue processing, max pending check, skip list, multi-filter LoadNextMsg/LoadNextMsgMulti | | consumer.processWaiting() | consumer.go:4645 | PARTIAL | WaitingRequestQueue.RemoveExpired() | .NET only removes expired; Go also checks interest, sends heartbeats, handles noWait EOS, replicated deliveries | | consumer.checkWaitingForInterest() | consumer.go:4745 | MISSING | — | Checks if any waiting requests still have interest | | consumer.hbTimer() | consumer.go:4751 | PORTED | PushConsumerEngine.StartIdleHeartbeatTimer() | | | consumer.checkAckFloor() | consumer.go:4762 | MISSING | — | Corrects ack floor drift when stream FirstSeq advances past consumer asflr; processes stale pending entries | | consumer.processInboundAcks() | consumer.go:4854 | PARTIAL | AckProcessor.ProcessAck() is synchronous | Go runs as dedicated goroutine with ack floor drift ticker; .NET processes inline | | consumer.processInboundNextMsgReqs() | consumer.go:4902 | PARTIAL | ConsumerApiHandlers.HandleNext() | Go runs as dedicated goroutine draining ipQueue; .NET handles synchronously per API call | | consumer.suppressDeletion() | consumer.go:4926 | MISSING | — | Resets inactivity timer on ack activity to prevent premature ephemeral deletion | | consumer.loopAndGatherMsgs() | consumer.go:4948 | PARTIAL | PushConsumerEngine.LoopAndGatherMsgsAsync() | .NET has basic gather loop; Go has full pause check, push active check, pull wait check, replay delay, rate limit, flow control, heartbeat timer |

| consumer.sendIdleHeartbeat() | consumer.go:5222 | PORTED | PushConsumerEngine.SendIdleHeartbeatCallback() | Includes stall header and pending counts | | consumer.ackReply() | consumer.go:5234 | MISSING | — | Formats $JS.ACK.{stream}.{consumer}.{dc}.{sseq}.{dseq}.{ts}.{pending} reply subject | | consumer.setMaxPendingBytes() | consumer.go:5239 | MISSING | — | Sets flow control byte limits; used in testing | | consumer.checkNumPending() | consumer.go:5252 | MISSING | — | Sanity-checks cached num pending against store state | | consumer.numPending() | consumer.go:5271 | MISSING | — | Returns cached pending count (npc clamped to 0) | | consumer.checkNumPendingOnEOF() | consumer.go:5281 | MISSING | — | Resets npc/npf when consumer has caught up to stream end | | consumer.streamNumPendingLocked() | consumer.go:5294 | MISSING | — | Acquires lock and delegates to streamNumPending | | consumer.streamNumPending() | consumer.go:5303 | MISSING | — | Forces recalculation of num pending from store | | consumer.calculateNumPending() | consumer.go:5319 | MISSING | — | Calculates num pending using NumPending/NumPendingMulti with filter awareness | | convertToHeadersOnly() | consumer.go:5336 | MISSING | — | Strips msg payload and replaces with Nats-Msg-Size header for HeadersOnly consumers | | consumer.deliverMsg() | consumer.go:5364 | PARTIAL | PushConsumerEngine.Enqueue() + RunDeliveryLoopAsync() | .NET enqueues frames and sends via loop; Go handles dseq tracking, pending tracking, flow control, replicated delivery, rate limiting, interest ack for AckNone | | consumer.replicateDeliveries() | consumer.go:5428 | NOT_APPLICABLE | — | Cluster-specific: checks if deliveries must be replicated before sending | | consumer.needFlowControl() | consumer.go:5432 | PARTIAL | PushConsumerEngine.IsFlowControlStalled | .NET tracks pending FC count; Go tracks pbytes vs maxpb threshold | | consumer.processFlowControl() | consumer.go:5448 | PARTIAL | PushConsumerEngine.AcknowledgeFlowControl() | .NET decrements count; Go also doubles maxpb (slow start ramp), updates pbytes accounting | | consumer.fcReply() | consumer.go:5476 | MISSING | — | Generates unique flow control reply subject: _FCR_.{stream}.{consumer}.{rand4} | | consumer.sendFlowControl() | consumer.go:5495 | PARTIAL | FC frame in PushConsumerEngine.RunDeliveryLoopAsync() | .NET sends FC frame; Go also tracks fcsz/fcid state |

| consumer.trackPending() | consumer.go:5507 | PARTIAL | AckProcessor.Register() | .NET registers with ackWaitMs; Go also handles backoff array indexing and ptmr reset | | consumer.creditWaitingRequest() | consumer.go:5541 | MISSING | — | Credits back a failed delivery in the wait queue (n++, d--) | | consumer.didNotDeliver() | consumer.go:5554 | MISSING | — | Handles failed delivery: decrements delivery count, checks push/pull mode, queues redelivery, checks delivery interest | | consumer.addToRedeliverQueue() | consumer.go:5595 | PORTED | RedeliveryTracker.Schedule() | .NET uses PriorityQueue; Go uses rdq slice + rdqi set | | consumer.hasRedeliveries() | consumer.go:5603 | PORTED | RedeliveryTracker.GetDue() returns non-empty | | | consumer.getNextToRedeliver() | consumer.go:5607 | PORTED | RedeliveryTracker.GetDue() enumeration | | | consumer.onRedeliverQueue() | consumer.go:5625 | PORTED | RedeliveryTracker.IsTracking() (via _deliveryCounts) | | | consumer.removeFromRedeliverQueue() | consumer.go:5631 | PORTED | RedeliveryTracker.Acknowledge() | Removes from entries and delivery counts | | consumer.checkPending() | consumer.go:5651 | PARTIAL | AckProcessor.TryGetExpired() | .NET checks one expired at a time; Go scans all pending with backoff, checks awl interlock, removes stale below fseq/asflr, sorts expired, adjusts timestamps |

| consumer.seqFromReply() | consumer.go:5770 | MISSING | — | Extracts delivery sequence from ack reply subject | | consumer.streamSeqFromReply() | consumer.go:5776 | MISSING | — | Extracts stream sequence from ack reply subject | | parseAckReplyNum() | consumer.go:5782 | MISSING | — | Fast ASCII digit parser for ack reply tokens | | replyInfo() | consumer.go:5798 | MISSING | — | Parses all 5 fields from $JS.ACK.{stream}.{consumer}.{dc}.{sseq}.{dseq}.{ts}.{pending} | | ackReplyInfo() | consumer.go:5821 | MISSING | — | Parses sseq, dseq, dc from ack reply subject |

| lastSeqSkipList (struct) | consumer.go:5849 | MISSING | — | Holds skip list for DeliverLastPerSubject startup | | consumer.hasSkipListPending() | consumer.go:5856 | MISSING | — | Checks if skip list has pending entries | | consumer.selectStartingSeqNo() | consumer.go:5861 | PARTIAL | PullConsumerEngine.ResolveInitialSequenceAsync() | .NET handles DeliverAll/Last/New/ByStartSeq/ByStartTime/LastPerSubject; Go also handles filtered subjects for DeliverLast, MaxMsgsPer optimization for LastPerSubject, MultiLastSeqs, time-based filtered skip-ahead, empty/future/past clamping | | consumer.nextSeq() | consumer.go:5841 | PORTED | ConsumerHandle.NextSequence property | |

| isDurableConsumer() | consumer.go:5969 | PORTED | ConsumerConfig.Ephemeral flag (inverse) | | | consumer.isDurable() | consumer.go:5973 | PORTED | !config.Ephemeral | | | consumer.isPushMode() | consumer.go:5978 | PORTED | ConsumerConfig.Push property | | | consumer.isPullMode() | consumer.go:5982 | PORTED | !config.Push | | | consumer.String() | consumer.go:5987 | NOT_APPLICABLE | — | Trivial name getter | | createConsumerName() | consumer.go:5994 | PORTED | Guid.NewGuid() in ConsumerManager | Different generation approach but same purpose | | stream.deleteConsumer() | consumer.go:5999 | PORTED | ConsumerManager.Delete() | | | consumer.getStream() | consumer.go:6003 | PORTED | ConsumerHandle.Stream property | | | consumer.streamName() | consumer.go:6010 | PORTED | ConsumerHandle.Stream property | | | consumer.isActive() | consumer.go:6021 | PARTIAL | ConsumerHandle.Paused (inverse) | .NET uses Paused; Go checks active flag + mset != nil | | consumer.hasNoLocalInterest() | consumer.go:6029 | PARTIAL | DeliveryInterestTracker.HasInterest (inverse) | .NET tracks subscriber count; Go checks sublist for delivery subject |

| consumer.purge() | consumer.go:6040 | MISSING | — | Called when parent stream is purged; adjusts sseq/asflr, clears stale pending, filters wider purge, updates store state | | stopAndClearTimer() | consumer.go:6124 | NOT_APPLICABLE | — | Go timer helper; .NET uses Timer.Dispose() | | consumer.stop() | consumer.go:6135 | PARTIAL | PushConsumerEngine.StopDeliveryLoop() + StopGatherLoop() | .NET stops loops; Go has full stopWithFlags with advisory, cleanup, subscription unsubscribe | | consumer.deleteWithoutAdvisory() | consumer.go:6139 | MISSING | — | Deletes without sending advisory | | consumer.delete() | consumer.go:6144 | PORTED | ConsumerManager.Delete() | | | consumer.isClosed() | consumer.go:6149 | MISSING | — | Checks closed flag under lock | | consumer.stopWithFlags() | consumer.go:6155 | MISSING | — | Full lifecycle shutdown: cluster assignment check, advisory, subscription cleanup, client close, interest clear, store delete/stop, RAFT node stop, directory cleanup | | consumer.cleanupNoInterestMessages() | consumer.go:6334 | MISSING | — | Removes messages with no remaining consumer interest; used on interest-policy stream consumer deletion | | deliveryFormsCycle() | consumer.go:6400 | MISSING | — | Validates that delivery subject doesn't create a cycle with stream subjects | | consumer.switchToEphemeral() | consumer.go:6410 | MISSING | — | Converts durable to ephemeral on startup recovery; clears Durable, updates inactive threshold | | consumer.requestNextMsgSubject() | consumer.go:6430 | MISSING | — | Returns the subject for next-message pull requests |

| consumer.decStreamPending() | consumer.go:6434 | MISSING | — | Decrements cached num pending on message deletion; processes pending term if message was pending | | consumer.account() | consumer.go:6459 | NOT_APPLICABLE | — | Account getter | | consumer.signalSubs() | consumer.go:6468 | MISSING | — | Creates sublist filter subjects for stream signal registration | | consumer.processStreamSignal() | consumer.go:6494 | PARTIAL | PushConsumerEngine.Signal(ConsumerSignal.NewMessage) | .NET signals via channel; Go checks leader, updates npc, checks push active / pull waiting | | subjectSliceEqual() | consumer.go:6517 | NOT_APPLICABLE | — | Utility set equality; trivial | | gatherSubjectFilters() | consumer.go:6536 | NOT_APPLICABLE | — | Utility to collect filter strings; trivial |

| consumer.shouldStartMonitor() | consumer.go:6546 | MISSING | — | Atomically checks/sets monitor running flag with WaitGroup | | consumer.clearMonitorRunning() | consumer.go:6560 | MISSING | — | Clears monitor running flag and decrements WaitGroup | | consumer.isMonitorRunning() | consumer.go:6571 | MISSING | — | Checks monitor running flag | | consumer.checkStateForInterestStream() | consumer.go:6582 | MISSING | — | For interest/WQ streams: walks sequences from FirstSeq to ack floor, acks already-consumed messages; handles pending above floor; adjusts chkflr |

| consumer.resetPtmr() | consumer.go:6692 | PARTIAL | Timer in AckProcessor.TryGetExpired() loop | Go uses AfterFunc timer; .NET checks expiry on poll | | consumer.stopAndClearPtmr() | consumer.go:6701 | PARTIAL | — | Go stops timer and clears; .NET has no dedicated pending timer | | consumer.resetPendingDeliveries() | consumer.go:6706 | MISSING | — | Recycles pending and waiting delivery pool entries; clustered delivery cleanup |

| Status | Count | | PORTED | 31 | | PARTIAL | 28 | | MISSING | 37 | | NOT_APPLICABLE | 9 | | DEFERRED | 0 | | Total | 105 |

| memStore struct | memstore.go:33 | PARTIAL | MemStore class in MemStore.cs:16 | .NET uses Dictionary<string,SubjectState> instead of stree.SubjectTree[SimpleState]; no scb/rmcb/pmsgcb callbacks; no ageChk timer; no scheduling; no sdm | | newMemStore | memstore.go:54 | PORTED | MemStore(StreamConfig) constructor, MemStore.cs:111 | TTL init present; FirstSeq handled; no ats.Register() | | UpdateConfig | memstore.go:86 | PARTIAL | IStreamStore.UpdateConfig, MemStore.cs:799 | TTL create/destroy ported; per-subject limit enforcement ported; missing: age timer start/stop, enforceMsgLimit/enforceBytesLimit on config change, scheduling support | | recoverTTLState | memstore.go:147 | MISSING | -- | TTL state recovery from existing messages not implemented | | recoverMsgSchedulingState | memstore.go:171 | MISSING | -- | Message scheduling not implemented |

| storeRawMsg (internal) | memstore.go:195 | PARTIAL | StoreInternal, MemStore.cs:872 | Core store logic ported (seq check, per-subject tracking, msg/bytes limits); missing: DiscardNew policy checks, DiscardNewPer check, TTL tracking in THW, age timer management, scheduling support | | StoreRawMsg | memstore.go:329 | PARTIAL | IStreamStore.StoreRawMsg, MemStore.cs:299 | Delegates to StoreInternal; missing: scb callback, receivedAny first-message age check | | StoreMsg | memstore.go:350 | PORTED | IStreamStore.StoreMsg, MemStore.cs:287 | Core logic matches Go | | SkipMsg | memstore.go:368 | PORTED | IStreamStore.SkipMsg, MemStore.cs:308 | Sequence check and dmap handling present | | SkipMsgs | memstore.go:395 | PORTED | IStreamStore.SkipMsgs, MemStore.cs:332 | Multi-skip ported | | FlushAllPending | memstore.go:424 | PORTED | IStreamStore.FlushAllPending, MemStore.cs:358 | No-op in both |

| RegisterStorageUpdates | memstore.go:431 | MISSING | -- | Storage update callback not implemented | | RegisterStorageRemoveMsg | memstore.go:439 | MISSING | -- | Removal callback not implemented | | RegisterProcessJetStreamMsg | memstore.go:446 | MISSING | -- | JetStream msg processing callback not implemented |

| GetSeqFromTime | memstore.go:454 | PORTED | IStreamStore.GetSeqFromTime, MemStore.cs:571 | Binary search with gap awareness ported | | FilteredState | memstore.go:531 | PORTED | IStreamStore.FilteredState, MemStore.cs:639 | Delegates to internal method | | filteredStateLocked | memstore.go:540 | PARTIAL | FilteredStateLocked, MemStore.cs (internal) | Core matching ported; lacks lastPerSubject partial-scan optimization, firstNeedsUpdate/lastNeedsUpdate lazy recalculation | | SubjectsState | memstore.go:748 | PORTED | IStreamStore.SubjectsState, MemStore.cs:643 | Implemented with Dictionary instead of SubjectTree | | AllLastSeqs | memstore.go:780 | PORTED | IStreamStore.AllLastSeqs, MemStore.cs:679 | Sorted last sequences | | filterIsAll | memstore.go:811 | MISSING | -- | Helper to check if filters == stream subjects | | MultiLastSeqs | memstore.go:828 | PORTED | IStreamStore.MultiLastSeqs, MemStore.cs:691 | Matching logic ported | | SubjectsTotals | memstore.go:881 | PORTED | IStreamStore.SubjectsTotals, MemStore.cs:664 | Per-subject counts ported | | NumPending | memstore.go:913 | PORTED | IStreamStore.NumPending, MemStore.cs:747 | Delegates to filteredStateLocked | | NumPendingMulti | memstore.go:923 | MISSING | -- | Multi-subject sublist-based pending count not implemented |

| enforcePerSubjectLimit | memstore.go:1072 | PORTED | EnforcePerSubjectLimit, MemStore.cs (internal) | Removes oldest per-subject messages | | enforceMsgLimit | memstore.go:1088 | PARTIAL | Inline in StoreInternal | Logic present but not separated into a named method; DiscardOld policy not checked | | enforceBytesLimit | memstore.go:1102 | PARTIAL | Inline in StoreInternal | Similar to enforceMsgLimit |

| startAgeChk | memstore.go:1116 | MISSING | -- | Age check timer not implemented | | resetAgeChk | memstore.go:1126 | MISSING | -- | Age check timer reset not implemented | | cancelAgeChk | memstore.go:1194 | MISSING | -- | Age check cancellation not implemented | | expireMsgs | memstore.go:1203 | MISSING | -- | Full MaxAge + TTL expiration loop not implemented | | shouldProcessSdm | memstore.go:1322 | MISSING | -- | Subject delete marker tracking not implemented | | shouldProcessSdmLocked | memstore.go:1329 | MISSING | -- | SDM tracking internals | | handleRemovalOrSdm | memstore.go:1362 | MISSING | -- | SDM/removal handler | | runMsgScheduling | memstore.go:1383 | MISSING | -- | Message scheduling not implemented |

| PurgeEx | memstore.go:1422 | PORTED | IStreamStore.PurgeEx, MemStore.cs:481 | Subject-specific + keep + seq purge ported | | Purge | memstore.go:1471 | PORTED | IStreamStore.Purge, MemStore.cs:472 | Full purge ported | | purge (internal) | memstore.go:1475 | PORTED | PurgeInternal, MemStore.cs | Resets msgs/fss/dmap | | Compact | memstore.go:1509 | PORTED | IStreamStore.Compact, MemStore.cs:533 | Compaction ported | | compact (internal) | memstore.go:1513 | PORTED | CompactInternal, MemStore.cs | Removes messages before seq | | reset | memstore.go:1583 | PORTED | IStreamStore.Truncate(0), MemStore.cs:540 | Full reset handled via Truncate(0) | | Truncate | memstore.go:1618 | PORTED | IStreamStore.Truncate, MemStore.cs:536 | Removes messages after seq |

| SubjectForSeq | memstore.go:1678 | PORTED | IStreamStore.SubjectForSeq, MemStore.cs:736 | | | LoadMsg | memstore.go:1692 | PORTED | IStreamStore.LoadMsg, MemStore.cs:361 | | | loadMsgLocked | memstore.go:1697 | PORTED | Inline in LoadMsg | Lock parameter not needed (.NET uses lock(_gate)) | | LoadLastMsg | memstore.go:1724 | PORTED | IStreamStore.LoadLastMsg, MemStore.cs:393 | Wildcard + literal + fwcs paths | | loadLastLocked | memstore.go:1733 | PORTED | Inline in LoadLastMsg | | | LoadNextMsgMulti | memstore.go:1763 | MISSING | -- | Multi-subject sublist-based next message not implemented | | LoadNextMsg | memstore.go:1798 | PARTIAL | IStreamStore.LoadNextMsg, MemStore.cs:372 | Linear scan only; missing shouldLinearScan optimization, nextWildcardMatchLocked, nextLiteralMatchLocked | | nextWildcardMatchLocked | memstore.go:1810 | MISSING | -- | FSS-based wildcard bounds optimization | | nextLiteralMatchLocked | memstore.go:1852 | MISSING | -- | FSS-based literal bounds optimization | | shouldLinearScan | memstore.go:1868 | MISSING | -- | Linear scan decision helper | | loadNextMsgLocked | memstore.go:1877 | PARTIAL | Inline in LoadNextMsg | Core linear scan ported; FSS-based optimizations missing | | LoadPrevMsg | memstore.go:1925 | PORTED | IStreamStore.LoadPrevMsg, MemStore.cs:439 | Backward walk ported | | LoadPrevMsgMulti | memstore.go:1952 | MISSING | -- | Multi-subject sublist-based prev message not implemented |

| RemoveMsg | memstore.go:1987 | PORTED | IStreamStore.RemoveMsg, MemStore.cs:454 | | | EraseMsg | memstore.go:1995 | PARTIAL | IStreamStore.EraseMsg, MemStore.cs:463 | Does not overwrite with random bytes (secure erase) | | updateFirstSeq | memstore.go:2004 | PORTED | Inline in RemoveInternal | Updates first seq on removal | | removeSeqPerSubject | memstore.go:2037 | PORTED | RemoveSeqPerSubject, MemStore.cs | Per-subject tracking update on remove | | recalculateForSubj | memstore.go:2070 | MISSING | -- | Lazy first/last recalculation for per-subject state (uses firstNeedsUpdate/lastNeedsUpdate flags) | | removeMsg (internal) | memstore.go:2110 | PARTIAL | RemoveInternal, MemStore.cs | Core removal ported; missing: TTL removal from THW, secure erase with random bytes, scb callback | | deleteFirstMsgOrPanic | memstore.go:1667 | PORTED | Inline in limit enforcement | | | deleteFirstMsg | memstore.go:1673 | PORTED | Inline in limit enforcement | |

| Type | memstore.go:2167 | PORTED | IStreamStore.Type, MemStore.cs:797 | Returns StorageType.Memory | | FastState | memstore.go:2173 | PORTED | IStreamStore.FastState, MemStore.cs:781 | Populates ref struct | | State | memstore.go:2192 | PORTED | IStreamStore.State, MemStore.cs:757 | Full state with deleted list | | Utilization | memstore.go:2221 | MISSING | -- | Returns (total, reported) byte counts | | memStoreMsgSize | memstore.go:2231 | PORTED | MsgSize, MemStore.cs (internal) | Size calculation for accounting | | memStoreMsgSizeRaw | memstore.go:2227 | PORTED | Inline in MsgSize | | | ResetState | memstore.go:2236 | PORTED | IStreamStore.ResetState, MemStore.cs:846 | No-op (scheduling not implemented) | | Delete | memstore.go:2245 | PORTED | IStreamStore.Delete, MemStore.cs:831 | | | Stop | memstore.go:2249 | PORTED | IStreamStore.Stop, MemStore.cs:828 | | | isClosed | memstore.go:2272 | MISSING | -- | Closed check (msgs == nil) | | EncodedStreamState | memstore.go:2322 | PARTIAL | IStreamStore.EncodedStreamState, MemStore.cs:849 | Returns empty array stub — binary encoding not implemented | | SyncDeleted | memstore.go:2357 | MISSING | -- | Delete block synchronization for NRG not implemented |

| consumerMemStore struct | memstore.go:2278 | MISSING | -- | In-memory consumer state store not implemented as a distinct type | | ConsumerStore (factory) | memstore.go:2286 | MISSING | -- | Consumer store creation stub; returns NotSupportedException | | AddConsumer | memstore.go:2301 | MISSING | -- | Consumer count tracking | | RemoveConsumer | memstore.go:2308 | MISSING | -- | Consumer count tracking | | Snapshot | memstore.go:2317 | NOT_APPLICABLE | -- | Returns "no impl" in Go too | | consumerMemStore.Update | memstore.go:2382 | MISSING | -- | Consumer state update | | consumerMemStore.SetStarting | memstore.go:2428 | MISSING | -- | Set starting sequence | | consumerMemStore.UpdateStarting | memstore.go:2437 | MISSING | -- | Update starting sequence | | consumerMemStore.Reset | memstore.go:2451 | MISSING | -- | Reset consumer state | | consumerMemStore.HasState | memstore.go:2459 | MISSING | -- | Check if state exists | | consumerMemStore.UpdateDelivered | memstore.go:2466 | MISSING | -- | Update delivery tracking | | consumerMemStore.UpdateAcks | memstore.go:2532 | MISSING | -- | Ack processing (AckAll / AckExplicit) | | consumerMemStore.UpdateConfig | memstore.go:2606 | MISSING | -- | Update consumer config | | consumerMemStore.Stop | memstore.go:2615 | MISSING | -- | Stop consumer store | | consumerMemStore.Delete | memstore.go:2624 | MISSING | -- | Delete consumer store | | consumerMemStore.StreamDelete | memstore.go:2628 | MISSING | -- | Stream-level delete | | consumerMemStore.State | memstore.go:2632 | MISSING | -- | Get consumer state | | consumerMemStore.BorrowState | memstore.go:2638 | MISSING | -- | Borrow state (no copy) | | consumerMemStore.EncodedState | memstore.go:2672 | MISSING | -- | Binary-encode consumer state | | consumerMemStore.Type | memstore.go:2700 | MISSING | -- | Returns MemoryStorage |

| FileStoreConfig struct | filestore.go:55 | PORTED | FileStoreConfig class, FileStoreConfig.cs:12 | All fields ported (StoreDir, BlockSize, CacheExpire, SubjectStateExpire, SyncInterval, SyncAlways, AsyncFlush, Cipher, Compression); missing: srv internal reference | | FileStreamInfo | filestore.go:80 | MISSING | -- | Created + StreamConfig wrapper not defined | | StoreCipher enum | filestore.go:85 | PORTED | StoreCipher enum, AeadEncryptor.cs:22 | ChaCha, AES, NoCipher | | StoreCompression enum | filestore.go:106 | PORTED | StoreCompression enum, AeadEncryptor.cs:39 | NoCompression, S2Compression | | StoreCompression.String/MarshalJSON/UnmarshalJSON | filestore.go:113-151 | NOT_APPLICABLE | -- | .NET enums have built-in string conversion; JSON handled by System.Text.Json | | FileConsumerInfo | filestore.go:154 | MISSING | -- | Consumer info with Created + Name + Config | | psi struct | filestore.go:166 | MISSING | -- | Per-subject index (total, fblk, lblk) for PSIM tree | | fileStore struct | filestore.go:172 | PARTIAL | FileStore class, FileStore.cs:23 | .NET uses in-memory Dictionary instead of block-based PSIM; missing: psim SubjectTree, bim block index map, tombs, ld, callbacks (scb/rmcb/pmsgcb), age timer, sync timer, prf/aek encryption keys, hh highway hash, qch/fsld channels, async flush state | | msgBlock struct | filestore.go:217 | PARTIAL | MsgBlock class, MsgBlock.cs:24 | Basic block file + index + delete tracking ported; missing: encryption (aek/bek/seed/nonce), compression (cmp), FSS subject tree, cache expiry timer (ctmr), write-error tracking (werr), fch/qch channels, loading/flusher flags, compact/sync flags | | cache struct | filestore.go:270 | PARTIAL | _cache Dictionary in MsgBlock.cs:49 | .NET uses Dictionary<ulong,MessageRecord>; Go uses byte-buffer + index array | | msgId struct | filestore.go:278 | MISSING | -- | Sequence+timestamp pair | | Constants (magic, version, dirs, sizes) | filestore.go:283-377 | PARTIAL | -- | Some constants like block sizes defined differently in FileStoreOptions; most Go constants (magic bytes, dir names, scan patterns, thresholds) not ported |

| newFileStore | filestore.go:379 | PARTIAL | FileStore constructor, FileStore.cs | .NET creates directory + first block; missing: dynBlkSize, encryption key setup, highway hash init, full recovery pipeline | | newFileStoreWithCreated | filestore.go:383 | PARTIAL | (merged into constructor) | Core directory setup present; missing: prf/oldprf key gen, AEK recovery, full state recovery, TTL/scheduling recovery, tombstone processing, meta file write, sync timer, flush state loop | | lockAllMsgBlocks/unlockAllMsgBlocks | filestore.go:641-653 | NOT_APPLICABLE | -- | .NET uses different concurrency model | | UpdateConfig | filestore.go:655 | PARTIAL | IStreamStore.UpdateConfig in FileStore.cs | Basic config update present; missing: meta file write, TTL/scheduling, limits enforcement, async flush toggle | | dynBlkSize | filestore.go:763 | MISSING | -- | Dynamic block size calculation based on retention/maxBytes/encryption |

| genEncryptionKey | filestore.go:800 | PORTED | AeadEncryptor.Encrypt/Decrypt, AeadEncryptor.cs:73 | ChaCha20-Poly1305 and AES-GCM both supported | | genEncryptionKeys | filestore.go:816 | MISSING | -- | Key encryption key generation with PRF not ported | | genBlockEncryptionKey | filestore.go:864 | MISSING | -- | Block-level stream cipher (ChaCha20/AES-CTR) not ported | | recoverAEK | filestore.go:878 | MISSING | -- | AEK recovery from key file | | setupAEK | filestore.go:907 | MISSING | -- | AEK initial setup | | writeStreamMeta | filestore.go:929 | MISSING | -- | Stream metadata + checksum write | | loadEncryptionForMsgBlock | filestore.go:1078 | MISSING | -- | Per-block encryption key loading | | convertCipher | filestore.go:1318 | MISSING | -- | Cipher conversion between ChaCha/AES | | convertToEncrypted | filestore.go:1407 | MISSING | -- | Plaintext to encrypted block conversion |

| getMsgBlockBuf/recycleMsgBlockBuf | filestore.go:996-1032 | MISSING | -- | Pooled block buffers (Go sync.Pool); .NET uses GC | | msgHdrSize/checksumSize/emptyRecordLen | filestore.go:1034-1038 | PARTIAL | MessageRecord.Encode/Decode in MessageRecord.cs | .NET uses its own binary format (not identical to Go's 22-byte header) | | noTrackSubjects | filestore.go:1041 | MISSING | -- | Helper to check if subject tracking is needed | | initMsgBlock | filestore.go:1046 | PARTIAL | MsgBlock.Create, MsgBlock.cs:174 | Basic block init; missing highway hash, cache/sync config |

| checkAndLoadEncryption | filestore.go:1068 | MISSING | -- | Encryption check on block load | | ensureLastChecksumLoaded | filestore.go:1139 | MISSING | -- | Lazy last checksum load | | recoverMsgBlock | filestore.go:1148 | PARTIAL | MsgBlock.Recover, MsgBlock.cs:188 | Basic file scan + index rebuild present; missing: encryption handling, index file check, FSS population, lost data tracking | | lostData/addLostData/removeFromLostData | filestore.go:1224-1275 | MISSING | -- | Lost data tracking not implemented | | rebuildState/rebuildStateLocked | filestore.go:1277-1315 | PARTIAL | -- | FileStore does a simplified rebuild; Go's full block-by-block state aggregation not ported | | rebuildStateLocked (msgBlock) | filestore.go:1454 | MISSING | -- | Per-block state rebuild from raw buffer | | rebuildStateFromBufLocked | filestore.go:1493 | MISSING | -- | Detailed record-by-record scan with tombstone/ebit/gap detection |

| warn/debug (logging) | filestore.go:1708-1724 | NOT_APPLICABLE | -- | .NET uses ILogger | | updateTrackingState | filestore.go:1727 | MISSING | -- | Helper to aggregate per-block state | | trackingStatesEqual | filestore.go:1743 | MISSING | -- | State consistency check | | recoverFullState | filestore.go:1754 | MISSING | -- | Full state recovery from index.db | | recoverTTLState | filestore.go:2042 | MISSING | -- | TTL hash wheel recovery from thw.db | | recoverMsgSchedulingState | filestore.go:2123 | MISSING | -- | Message scheduling recovery from sched.db | | lastChecksum (msgBlock) | filestore.go:2204 | PARTIAL | MsgBlock.LastChecksum, MsgBlock.cs:155 | Checksum tracked on write; missing: load from encrypted block | | cleanupOldMeta | filestore.go:2236 | MISSING | -- | Remove legacy .idx/.fss files | | recoverMsgs | filestore.go:2263 | PARTIAL | Recovery in FileStore constructor | Basic block scan + re-open present; missing: per-block first/last propagation, tombstone handling, orphan key cleanup | | expireMsgsOnRecover | filestore.go:2401 | MISSING | -- | Startup age expiration | | copyMsgBlocks | filestore.go:2589 | NOT_APPLICABLE | -- | Go slice copy helper |

| GetSeqFromTime (fs) | filestore.go:2600 | PARTIAL | In FileStore.cs | Basic implementation present; missing: block selection by timestamp, binary search across blocks | | firstMatchingMulti (mb) | filestore.go:2666 | MISSING | -- | Block-level multi-subject first match | | firstMatching (mb) | filestore.go:2806 | MISSING | -- | Block-level first matching with FSS optimization | | prevMatchingMulti (mb) | filestore.go:2948 | MISSING | -- | Block-level reverse multi-subject match | | filteredPending / filteredPendingLocked (mb) | filestore.go:3062-3188 | MISSING | -- | Per-block filtered pending count | | FilteredState (fs) | filestore.go:3191 | PARTIAL | In FileStore.cs | Simplified version; missing: per-block aggregation with FSS | | checkSkipFirstBlock | filestore.go:3241 | MISSING | -- | Block skip optimization using PSIM | | checkSkipFirstBlockMulti | filestore.go:3269 | MISSING | -- | Multi-subject block skip | | selectSkipFirstBlock | filestore.go:3287 | MISSING | -- | Block index selection helper | | numFilteredPending / numFilteredPendingNoLast / numFilteredPendingWithLast | filestore.go:3308-3410 | MISSING | -- | Optimized filtered pending using PSIM | | SubjectsState (fs) | filestore.go:3413 | PARTIAL | In FileStore.cs | In-memory implementation; missing: per-block FSS aggregation | | AllLastSeqs / allLastSeqsLocked (fs) | filestore.go:3495-3553 | PARTIAL | In FileStore.cs | In-memory implementation; missing: reverse block walk with FSS | | filterIsAll (fs) | filestore.go:3558 | MISSING | -- | Filter optimization helper | | MultiLastSeqs (fs) | filestore.go:3575 | PARTIAL | In FileStore.cs | In-memory implementation; missing: PSIM-based optimization, per-block walk | | NumPending (fs) | filestore.go:3710 | PARTIAL | In FileStore.cs | Simplified version; missing: PSIM optimization, block-level aggregation |

| Status | MemStore | FileStore (1-4000) | Total | | PORTED | 33 | 4 | 37 | | PARTIAL | 11 | 16 | 27 | | MISSING | 36 | 35 | 71 | | NOT_APPLICABLE | 1 | 4 | 5 | | DEFERRED | 0 | 0 | 0 | | Total | 81 | 59 | 140 |

| fs.NumPendingMulti | filestore.go:4051 | MISSING | -- | Multi-filter NumPending using SimpleSublist; consumer optimization path | | fs.SubjectsTotals | filestore.go:4387 | PORTED | FileStore.SubjectsTotals | .NET iterates _messages dict; Go uses psim trie Match | | fs.subjectsTotalsLocked | filestore.go:4394 | PORTED | (inlined in SubjectsTotals) | Internal locked helper | | fs.RegisterStorageUpdates | filestore.go:4412 | MISSING | -- | Callback registration for storage change notifications | | fs.RegisterStorageRemoveMsg | filestore.go:4424 | MISSING | -- | Callback registration for message removals (used by replicated streams) | | fs.RegisterProcessJetStreamMsg | filestore.go:4431 | MISSING | -- | Callback registration for new JetStream message processing | | fs.hashKeyForBlock | filestore.go:4439 | MISSING | -- | HighwayHash key derivation per block index | | mb.setupWriteCache | filestore.go:4443 | PARTIAL | MsgBlock._cache / WriteCacheManager | .NET has a cache dict + WriteCacheManager; Go has elastic pointer, cache expiry timer, and loadMsgs fallback | | mb.finishedWithCache | filestore.go:4477 | PARTIAL | WriteCacheManager.EvictBlock | .NET evicts on block rotation; Go weakens elastic reference when no pending writes | | fs.newMsgBlockForWrite | filestore.go:4485 | PARTIAL | FileStore.RotateBlock | .NET creates new MsgBlock; Go also handles flush of pending, cache recycling, HighwayHash init, encryption key gen, flush loop spin-up | | fs.genEncryptionKeysForBlock | filestore.go:4575 | MISSING | -- | Per-block AEAD key generation and keyfile writing; .NET uses per-payload AEAD instead | | fs.storeRawMsg (internal) | filestore.go:4599 | PARTIAL | FileStore.StoreRawMsg | .NET stores but lacks: per-subject max enforcement (MaxMsgsPer), DiscardNew checks, psim updates, enforceMsgLimit/enforceBytesLimit calls, per-message TTL wheel, message scheduling | | fs.StoreRawMsg (exported) | filestore.go:4759 | PORTED | FileStore.StoreRawMsg | Public wrapper with callback | | fs.StoreMsg | filestore.go:4779 | PORTED | FileStore.StoreMsg | Returns (seq, ts); .NET simplified | | mb.skipMsg | filestore.go:4801 | PARTIAL | MsgBlock.WriteSkip | .NET writes skip record; Go also handles empty-block meta update, dmap insert, ebit flag | | fs.SkipMsg | filestore.go:4829 | PORTED | FileStore.SkipMsg | Sequence mismatch check, first/last update | | fs.SkipMsgs | filestore.go:4868 | PORTED | FileStore.SkipMsgs | .NET iterates SkipMsg; Go batch-inserts into dmap with single write placeholder | | fs.FlushAllPending | filestore.go:4933 | PORTED | FileStore.FlushAllPending | .NET flushes active block + writes stream.state | | fs.rebuildFirst | filestore.go:4940 | MISSING | -- | Rebuilds first-block state after removal errors | | fs.firstSeqForSubj | filestore.go:4966 | MISSING | -- | Optimized first-seq lookup per subject using psim fblk/lblk | | fs.enforceMsgLimit | filestore.go:5033 | MISSING | -- | Drop oldest messages when MaxMsgs exceeded; bulk purge of full blocks | | fs.enforceBytesLimit | filestore.go:5061 | MISSING | -- | Drop oldest messages when MaxBytes exceeded; bulk purge of full blocks | | fs.enforceMsgPerSubjectLimit | filestore.go:5091 | MISSING | -- | Complex per-subject enforcement with psim skew detection and rebuild | | fs.deleteFirstMsg | filestore.go:5222 | MISSING | -- | Trivial wrapper: removeMsgViaLimits(firstSeq) | | fs.removeMsgViaLimits | filestore.go:5229 | MISSING | -- | Remove via limits (no forced index update) | | fs.RemoveMsg | filestore.go:5235 | PORTED | FileStore.RemoveMsg | .NET simplified: removes from dict + soft-deletes in block | | fs.EraseMsg | filestore.go:5239 | PORTED | FileStore.EraseMsg | .NET does secure erase via MsgBlock.Delete(secureErase: true) | | fs.removePerSubject | filestore.go:5245 | MISSING | -- | Decrements psim per-subject counter, removes from trie at zero | | fs.removeMsg (internal) | filestore.go:5267 | PARTIAL | FileStore.RemoveMsg / FileStore.EraseMsg | .NET simplified; Go handles: tombstone writing, cache loading, per-subject tracking, FIFO optimization, out-of-order dmap insert, inline compaction, secure erase, callback | | fs.removeMsgFromBlock | filestore.go:5307 | PARTIAL | FileStore.DeleteInBlock | .NET delegates to MsgBlock.Delete; Go handles full per-block accounting, tombstone write, secure erase, FIFO selectNextFirst, dmap, inline compact, empty-block removal | | fs.removeMsgsInRange | filestore.go:5509 | MISSING | -- | Bulk removal in [first,last] with block-level purge optimization | | mb.shouldCompactInline | filestore.go:5553 | MISSING | -- | Heuristic: compact when rbytes > minimum and 2x savings possible | | mb.shouldCompactSync | filestore.go:5561 | MISSING | -- | Sync-time compaction heuristic | | mb.compact | filestore.go:5567 | MISSING | -- | Full block rewrite compaction | | mb.compactWithFloor | filestore.go:5576 | MISSING | -- | Compaction with tombstone cleanup; handles compression, encryption, dmap pruning | | mb.slotInfo | filestore.go:5735 | MISSING | -- | Cache index slot lookup for record offset/length | | fs.isClosed | filestore.go:5778 | PORTED | FileStore._stopped | Atomic bool in Go; simple bool in .NET | | mb.spinUpFlushLoop | filestore.go:5783 | MISSING | -- | Goroutine-based flush loop per block | | mb.spinUpFlushLoopLocked | filestore.go:5791 | MISSING | -- | Locked version of flush loop startup | | kickFlusher | filestore.go:5805 | MISSING | -- | Non-blocking channel send to wake flush goroutine | | mb.kickFlusher | filestore.go:5815 | MISSING | -- | Per-block flusher kick | | mb.setInFlusher | filestore.go:5821 | MISSING | -- | Flusher state tracking | | mb.clearInFlusher | filestore.go:5827 | MISSING | -- | Flusher cleanup, close channels | | mb.flushLoop | filestore.go:5842 | MISSING | -- | Background goroutine: coalesce pending writes, flush, close FDs when no longer last block | | mb.eraseMsg | filestore.go:5890 | PARTIAL | MsgBlock.Delete(secureErase) | .NET overwrites payload with random bytes; Go overwrites full record including header, recalculates hash, updates both cache and disk | | mb.truncate | filestore.go:5940 | MISSING | -- | Truncate block to target sequence; handles decompression/re-encryption, eof calc, per-subject reset | | mb.isEmpty | filestore.go:6046 | PARTIAL | MsgBlock.MessageCount == 0 | Go uses atomic first/last comparison | | mb.selectNextFirst | filestore.go:6051 | MISSING | -- | Walk dmap to find next non-deleted first sequence | | fs.selectNextFirst | filestore.go:6091 | MISSING | -- | Clean up empty leading blocks, advance first | | mb.resetCacheExpireTimer | filestore.go:6123 | MISSING | -- | Per-block timer reset for cache expiry | | mb.startCacheExpireTimer | filestore.go:6135 | MISSING | -- | Start per-block cache expiry timer | | mb.clearCacheAndOffset | filestore.go:6141 | PARTIAL | MsgBlock.ClearCache | .NET clears cache dict; Go also resets linear scan tracker | | mb.clearCache | filestore.go:6148 | PARTIAL | MsgBlock.ClearCache | .NET nulls cache dict; Go handles fss expiry, elastic pointer cleanup, buffer recycling | | mb.expireCache | filestore.go:6176 | PARTIAL | WriteCacheManager background tick | .NET uses 500ms periodic timer; Go uses per-block AfterFunc timer | | mb.tryForceExpireCache | filestore.go:6182 | MISSING | -- | Force expire by temporarily clearing timestamps | | mb.tryForceExpireCacheLocked | filestore.go:6189 | MISSING | -- | Locked force-expire | | mb.tryExpireWriteCache | filestore.go:6199 | MISSING | -- | Expire write cache on block rotation, return recyclable buffer | | mb.expireCacheLocked | filestore.go:6220 | PARTIAL | WriteCacheManager eviction logic | .NET time-based eviction; Go handles elastic pointer strengthening, pending write detection, fss separate expiry | | fs.startAgeChk | filestore.go:6277 | PARTIAL | FileStore.RegisterTtl + HashWheel | .NET uses HashWheel; Go uses AfterFunc timer | | fs.resetAgeChk | filestore.go:6287 | PARTIAL | (implicit in ExpireFromWheel) | Go has sophisticated next-expire calculation with minimum 250ms floor | | fs.cancelAgeChk | filestore.go:6355 | PARTIAL | (implicit in Dispose) | .NET disposes wheel; Go stops and nils timer | | fs.expireMsgs | filestore.go:6364 | PARTIAL | FileStore.ExpireFromWheel | .NET does basic seq removal; Go handles: negative TTL (never-expire), SDM processing, THW-based TTL expiry, sorted removal for SDM, age delta recalculation | | fs.shouldProcessSdm | filestore.go:6482 | MISSING | -- | Subject Delete Marker pending tracking | | fs.shouldProcessSdmLocked | filestore.go:6489 | MISSING | -- | Locked SDM state check with rate limiting | | fs.handleRemovalOrSdm | filestore.go:6522 | MISSING | -- | Either removes via callback or emits SDM header message | | fs.runMsgScheduling | filestore.go:6543 | MISSING | -- | Background message scheduling with repeating schedule support | | fs.checkAndFlushLastBlock | filestore.go:6581 | PARTIAL | FileStore.FlushAllPending | .NET flushes active block; Go also handles rebuild state on lost data | | fs.checkMsgs | filestore.go:6598 | MISSING | -- | Full checksum verification scan of all blocks | | mb.enableForWriting | filestore.go:6622 | NOT_APPLICABLE | -- | Go-specific: open file descriptor, spin up flusher; .NET MsgBlock always has FileStream open | | mb.writeTombstone | filestore.go:6646 | PARTIAL | MsgBlock.WriteSkip | .NET writes skip/tombstone via WriteSkip; Go uses tbit flag on sequence | | mb.writeTombstoneNoFlush | filestore.go:6652 | MISSING | -- | Tombstone write without flush (used in bulk operations) | | mb.writeMsgRecord | filestore.go:6660 | PORTED | MsgBlock.Write / MsgBlock.WriteAt | .NET has both auto-seq and explicit-seq variants | | mb.writeMsgRecordLocked | filestore.go:6669 | PARTIAL | MsgBlock.WriteAt (under lock) | .NET writes record + updates index/cache; Go handles: per-subject fss tracking, elastic pointer strengthening, buffer pool management, HighwayHash checksum, tombstone accounting, flush-in-place, flusher kick | | mb.pendingWriteSize | filestore.go:6821 | MISSING | -- | Go tracks pending = cache.buf - cache.wp; .NET writes synchronously | | mb.pendingWriteSizeLocked | filestore.go:6831 | MISSING | -- | Locked version | | mb.closeFDs | filestore.go:6843 | PARTIAL | MsgBlock.Dispose | .NET disposes FileStream; Go checks pending data first | | mb.closeFDsLocked | filestore.go:6849 | PARTIAL | MsgBlock.Dispose | .NET unconditional; Go returns error if pending data | | mb.closeFDsLockedNoCheck | filestore.go:6857 | PARTIAL | MsgBlock.Dispose | .NET disposes; Go just closes mfd | | mb.bytesPending | filestore.go:6867 | NOT_APPLICABLE | -- | Go write-cache pending slice; .NET writes synchronously (no pending buffer) | | mb.blkSize | filestore.go:6885 | PORTED | MsgBlock.BytesUsed | Returns total bytes including deleted | | mb.updateAccounting | filestore.go:6897 | PARTIAL | (inline in MsgBlock.Write/WriteAt) | .NET updates first/last/totalWritten; Go handles ebit, atomic first/last, rbytes/bytes split | | fs.checkLastBlock | filestore.go:6920 | PARTIAL | FileStore.EnsureActiveBlock | .NET rotates on IsSealed; Go checks rbytes + rl > BlockSize | | fs.writeMsgRecord | filestore.go:6933 | PARTIAL | FileStore.StoreMsg / StoreRawMsg | .NET writes via MsgBlock; Go checks msg too large, increments dirty counter | | fs.writeTombstone | filestore.go:6956 | MISSING | -- | fs-level tombstone with block size enforcement | | fs.writeTombstoneNoFlush | filestore.go:6968 | MISSING | -- | No-flush variant | | mb.recompressOnDiskIfNeeded | filestore.go:6978 | MISSING | -- | On-disk block recompression (S2) after block seal |

| Status | Count | | PORTED | 14 | | PARTIAL | 27 | | MISSING | 37 | | NOT_APPLICABLE | 2 | | Total | 80 |

| mb.recompressOnDiskIfNeeded (tail) | filestore.go:7000-7027 | PARTIAL | FileStore.TransformForPersist | .NET applies compression at write time (S2Codec); no post-hoc re-compression of existing blocks | | mb.atomicOverwriteFile | filestore.go:7030-7111 | MISSING | — | Go writes block to temp file then renames; .NET uses direct RandomAccess.Write with no atomic overwrite | | mb.decompressIfNeeded | filestore.go:7114-7132 | PORTED | FileStore.RestorePayload / S2Codec.Decompress | .NET decompresses via S2Codec in RestorePayload; metadata parsing differs | | mb.encryptOrDecryptIfNeeded | filestore.go:7135-7145 | PARTIAL | AeadEncryptor.Encrypt/Decrypt | .NET uses AEAD (ChaCha20/AES-GCM) not XOR stream cipher; no block-level BEK regeneration | | mb.ensureRawBytesLoaded | filestore.go:7148-7163 | MISSING | — | .NET MsgBlock tracks _writeOffset directly; no lazy raw-bytes stat from disk | | fs.syncBlocks | filestore.go:7166-7291 | MISSING | — | No periodic block sync timer; .NET uses FileStream.Flush(flushToDisk: true) on demand | | fs.selectMsgBlock | filestore.go:7296-7299 | PORTED | FileStore.FindBlockForSequence | Binary search over _blocks by sequence range | | fs.selectMsgBlockWithIndex | filestore.go:7302-7343 | PORTED | FileStore.FindBlockForSequence / FindFirstBlockAtOrAfter | Combined linear/binary search; .NET uses pure binary search | | fs.selectMsgBlockForStart (by time) | filestore.go:7348-7372 | MISSING | — | No time-based block selection; GetSeqFromTime does linear scan over _messages | | mb.indexCacheBuf | filestore.go:7376-7557 | MISSING | — | Go builds index+FSS from raw block buffer; .NET uses Dictionary<ulong,(long,int)> index from RebuildIndex (much simpler) | | mb.flushPendingMsgs | filestore.go:7560-7572 | PARTIAL | MsgBlock.Flush | .NET calls _file.Flush(flushToDisk: true); Go has pending write buffer with encryption and rebuild-on-error | | mb.writeAt | filestore.go:7577-7588 | PORTED | RandomAccess.Write in MsgBlock.Write/WriteAt | .NET uses RandomAccess.Write for positional I/O; Go uses dios semaphore for I/O gating | | mb.flushPendingMsgsLocked | filestore.go:7592-7694 | PARTIAL | MsgBlock.Flush | Go has complex pending-write logic with encryption, rebuild-on-error, sync-always mode; .NET is simpler flush | | mb.clearLoading | filestore.go:7697-7699 | NOT_APPLICABLE | — | Go loading-guard flag; .NET has no equivalent concurrent loading concern | | mb.loadMsgs / mb.loadMsgsWithLock | filestore.go:7703-7885 | PARTIAL | MsgBlock.RebuildIndex / MsgBlock.Read | Go loads full block into cache from disk with decrypt/decompress; .NET reads on-demand per-record | | mb.cacheAlreadyLoaded / mb.cacheNotLoaded | filestore.go:7711-7724 | NOT_APPLICABLE | — | Go weak-reference cache management; .NET uses simple Dictionary<ulong,MessageRecord>? cache | | mb.fssNotLoaded | filestore.go:7728-7730 | NOT_APPLICABLE | — | Go per-subject state tree tracking; .NET has no block-level FSS | | mb.openBlock | filestore.go:7734-7740 | NOT_APPLICABLE | — | Go opens block file with dios semaphore; .NET holds FileStream open for block lifetime | | mb.loadBlock | filestore.go:7745-7791 | PARTIAL | MsgBlock.RebuildIndex (disk read) | Go loads entire block file into pooled buffer; .NET reads record-by-record during recovery | | mb.fetchMsg / mb.fetchMsgNoCopy / mb.fetchMsgEx | filestore.go:7890-7940 | PORTED | MsgBlock.Read | .NET does cache-then-disk lookup; Go has copy/no-copy variants and expiry tracking | | Error sentinels (errNoCache, errDeletedMsg, etc.) | filestore.go:7943-7959 | PARTIAL | Exceptions in MsgBlock.Read / FileStore.LoadMsg | .NET uses null returns and KeyNotFoundException instead of sentinel errors | | Bit constants (cbit, dbit, hbit, ebit, tbit) | filestore.go:7973-7983 | PARTIAL | MessageRecord.Deleted flag | Go uses bit-packed flags in seq/rl fields; .NET uses explicit Deleted bool in MessageRecord | | mb.cacheLookup / mb.cacheLookupNoCopy / mb.cacheLookupEx | filestore.go:7988-8096 | PARTIAL | MsgBlock.Read (cache path) | .NET checks _cache dictionary then falls back to disk; Go has full slot-based index lookup with hash verification | | fs.sizeForSeq | filestore.go:8101-8112 | MISSING | — | No per-sequence size calculation helper | | fs.msgForSeq / fs.msgForSeqLocked | filestore.go:8117-8160 | PORTED | FileStore.LoadMsg | .NET does hash-map lookup then binary-search block fallback | | mb.msgFromBuf / mb.msgFromBufNoCopy / mb.msgFromBufEx | filestore.go:8165-8300 | PARTIAL | MessageRecord.Decode | Go parses wire-format from raw buffer with header support; .NET uses MessageRecord.Decode with simpler format | | fs.LoadMsg | filestore.go:8308-8350 | PORTED | FileStore.LoadMsg | Both implement sequence-based message loading with block selection | | fs.LoadLastMsg | filestore.go:8352-8400 | PORTED | FileStore.LoadLastMsg | Both support subject-filtered last-message lookup | | mb.firstMatching | filestore.go:8402-8470 | MISSING | — | Go's per-block first-matching scan with FSS optimization; .NET filters _messages dictionary | | mb.prevMatchingMulti | filestore.go:~8470-8500 | MISSING | — | Go's per-block reverse multi-filter scan; .NET has no equivalent | | fs.LoadNextMsg | filestore.go:8508-8577 | PORTED | FileStore.LoadNextMsg | Both support filtered forward scan; Go uses psim skip-ahead, .NET uses LINQ | | fs.LoadPrevMsg | filestore.go:8579-8631 | PORTED | FileStore.LoadPrevMsg | Both walk backward from start; .NET iterates _messages dictionary | | fs.LoadPrevMsgMulti | filestore.go:8633-8670 | MISSING | — | No multi-filter reverse load in .NET | | fs.Type | filestore.go:8673-8675 | PORTED | FileStore.Type() | Returns StorageType.File | | fs.numSubjects | filestore.go:8679-8681 | PARTIAL | FileStore.State() counts subjects | .NET counts in State() method; no dedicated numSubjects helper | | fs.numConsumers | filestore.go:8684-8688 | MISSING | — | No consumer count tracking in FileStore; Go uses cmu+cfs | | fs.FastState | filestore.go:8692-8711 | PORTED | FileStore.FastState | Both populate minimal state struct without allocating deleted arrays | | fs.State | filestore.go:8714-8756 | PORTED | FileStore.State | Both return full state with deleted sequences and subject counts | | fs.Utilization | filestore.go:8758-8768 | MISSING | — | No total/reported bytes utilization tracking across blocks | | fileStoreMsgSizeRaw / fileStoreMsgSize / fileStoreMsgSizeEstimate | filestore.go:8770-8785 | MISSING | — | Go wire-format size calculation; .NET uses MessageRecord.Encode length | | fs.ResetState | filestore.go:8788-8794 | PORTED | FileStore.ResetState | .NET is no-op (re-derives from blocks on construction); Go clears scheduling inflight | | mb.sinceLastActivity | filestore.go:8797-8812 | MISSING | — | Go tracks lwts/lrts/llts/lsts for cache expiry timing; .NET uses WriteCacheManager TTL | | mb.sinceLastWriteActivity | filestore.go:8816-8825 | MISSING | — | No separate write-activity tracking | | checkNewHeader | filestore.go:8827-8833 | MISSING | — | Go index file magic/version check; .NET uses JSON for stream state | | mb.readIndexInfo | filestore.go:8836-8935 | MISSING | — | Go reads binary index (.idx) files with varint encoding; .NET rebuilds from block scan | | fs.cacheLoads | filestore.go:8938-8948 | MISSING | — | Cache load counter; no equivalent metric in .NET | | fs.cacheSize | filestore.go:8951-8971 | MISSING | — | Cache size tracking; .NET WriteCacheManager.TotalCachedBytes is approximate | | fs.dmapEntries | filestore.go:8974-8982 | MISSING | — | Total dmap entries across blocks; .NET SequenceSet per block but no aggregate | | subjectsEqual / subjectsAll / compareFn | filestore.go:8986-9001 | PARTIAL | FileStore.SubjectMatchesFilter | .NET has unified SubjectMatchesFilter; Go has separate comparator functions | | fs.PurgeEx | filestore.go:9005-9194 | PORTED | FileStore.PurgeEx | Both support subject-filtered purge with keep/seq limits; Go has tombstone writing, .NET is simpler | | fs.Purge / fs.purge | filestore.go:9198-9313 | PORTED | FileStore.Purge | Both clear all messages; Go does atomic directory rename with tombstone, .NET does _messages.Clear() + block dispose | | fs.recoverPartialPurge | filestore.go:9316-9337 | MISSING | — | Crash recovery for partial purge (ndir/pdir cleanup); .NET has no partial-purge recovery | | fs.Compact / fs.compact | filestore.go:9342-9591 | PORTED | FileStore.Compact | Both remove messages below seq; Go has block-level compaction with encryption/compression, .NET is in-memory | | fs.reset | filestore.go:9594-9641 | PARTIAL | FileStore.Truncate(0) | .NET Truncate(0) clears everything; Go reset() resets to zero state with psim/sdm cleanup | | mb.tombs / mb.tombsLocked | filestore.go:9644-9682 | MISSING | — | Tombstone record scanning from raw block buffer; .NET has no tombstone concept | | mb.numPriorTombs / mb.numPriorTombsLocked | filestore.go:9685-9738 | MISSING | — | Count tombstones for prior blocks; .NET has no tombstone tracking | | fs.Truncate | filestore.go:9741-9925 | PORTED | FileStore.Truncate | Both remove messages above seq; Go has block-level truncation with tombstone writes, .NET is in-memory | | fs.lastSeq | filestore.go:9927-9932 | PORTED | FileStore._last field | Direct field access vs Go lock-guarded helper | | fs.numMsgBlocks | filestore.go:9935-9939 | PORTED | FileStore.BlockCount | Property returns _blocks.Count | | fs.addMsgBlock | filestore.go:9943-9947 | PORTED | FileStore.RotateBlock (inline) | .NET adds to _blocks list and sets _activeBlock | | fs.removeMsgBlockFromList | filestore.go:9951-9964 | PARTIAL | FileStore.DisposeAllBlocks | .NET only bulk-removes blocks; no individual block removal from list | | fs.removeMsgBlock | filestore.go:9968-9988 | MISSING | — | Individual block removal with tombstone writes for last-seq preservation | | fs.forceRemoveMsgBlock | filestore.go:9992-9995 | MISSING | — | Force removal (dirty close + remove from list) | | fs.purgeMsgBlock | filestore.go:9999-10054 | MISSING | — | Per-block purge with per-subject tracking cleanup and scheduling metadata | | mb.dirtyClose | filestore.go:10058-10062 | PARTIAL | MsgBlock.Dispose | .NET disposes file handle; Go clears cache, stops timers, closes channels | | mb.dirtyCloseWithRemove | filestore.go:10065-10103 | PARTIAL | MsgBlock.Dispose + FileStore.CleanBlockFiles | Go closes and optionally removes files; .NET separates disposal from file cleanup | | mb.removeSeqPerSubject | filestore.go:10107-10145 | MISSING | — | Per-block per-subject state tracking with lazy first/last recalculation | | mb.recalculateForSubj | filestore.go:10149-10259 | MISSING | — | Scan cache buffer to recalculate first/last seq for a subject within a block | | fs.resetGlobalPerSubjectInfo | filestore.go:10262-10271 | MISSING | — | Rebuild psim (global per-subject index map) from all blocks | | mb.resetPerSubjectInfo / mb.generatePerSubjectInfo | filestore.go:10274-10339 | MISSING | — | Per-block subject tree (FSS) generation from block scan | | mb.ensurePerSubjectInfoLoaded | filestore.go:10343-10356 | MISSING | — | Lazy FSS loading guard; .NET has no block-level subject tracking | | fs.populateGlobalPerSubjectInfo | filestore.go:10360-10383 | MISSING | — | Populate psim from block FSS during recovery | | mb.close | filestore.go:10386-10424 | PORTED | MsgBlock.Dispose | Both close file handles; Go also flushes pending, clears FSS, stops timers | | fs.closeAllMsgBlocks | filestore.go:10426-10430 | PORTED | FileStore.DisposeAllBlocks | Both iterate and close/dispose all blocks | | fs.Delete | filestore.go:10432-10511 | PORTED | FileStore.Delete | Both stop and remove all data; Go has async directory removal with dios gating | | fs.setSyncTimer / fs.cancelSyncTimer | filestore.go:10514-10532 | MISSING | — | Periodic sync timer with jitter; .NET has no equivalent timer | | Full state magic/version constants | filestore.go:10537-10541 | MISSING | — | Binary full-state format versioning; .NET uses JSON | | fs.flushStreamStateLoop | filestore.go:10544-10571 | MISSING | — | Background goroutine for periodic state flush; .NET writes on FlushAllPending call | | timestampNormalized | filestore.go:10574-10579 | PARTIAL | Inline in FileStore methods | .NET normalizes via DateTimeOffset.ToUnixTimeMilliseconds | | fs.writeFullState / fs._writeFullState | filestore.go:10583-10831 | PARTIAL | FileStore.WriteStreamStateAsync | Go writes binary-encoded full state with psim, block metadata, checksums; .NET writes JSON snapshot | | fs.writeTTLState | filestore.go:10833-10845 | MISSING | — | TTL state persistence; .NET uses in-memory HashWheel only | | fs.writeMsgSchedulingState | filestore.go:10847-10859 | MISSING | — | Message scheduling state persistence | | fs.Stop / fs.stop | filestore.go:10862-10940 | PORTED | FileStore.Stop | Both flush and close; Go also stops consumer stores, cancels timers, writes full state | | fs.streamSnapshot | filestore.go:10945-10997+ | PARTIAL | FileStore.CreateSnapshotAsync | .NET creates JSON snapshot; Go creates S2-compressed tar archive with block files |

| Status | Count | | PORTED | 26 | | PARTIAL | 19 | | MISSING | 32 | | NOT_APPLICABLE | 5 | | DEFERRED | 0 | | Total | 82 |

| mb.dirtyClose() | filestore.go:10058 | PARTIAL | MsgBlock.Dispose() | .NET disposes file handle; Go also stops cache timer, closes fds without flush, optionally removes files | | mb.dirtyCloseWithRemove(remove) | filestore.go:10065 | PARTIAL | MsgBlock.Dispose() | .NET has no remove-on-close path; Go removes .blk and key files when remove=true | | mb.removeSeqPerSubject(subj, seq) | filestore.go:10107 | MISSING | — | Per-subject index tracking within a block; .NET MsgBlock has no per-subject FSS tree | | mb.recalculateForSubj(subj, ss) | filestore.go:10149 | MISSING | — | Scans cache to recalculate first/last seq for a subject within a block | | mb.resetPerSubjectInfo() | filestore.go:10274 | MISSING | — | Clears and regenerates per-subject info for a block | | mb.generatePerSubjectInfo() | filestore.go:10281 | MISSING | — | Builds per-subject SimpleState tree (fss) from block cache | | mb.ensurePerSubjectInfoLoaded() | filestore.go:10343 | MISSING | — | Lazy-loads per-subject info when first needed | | mb.close(sync) | filestore.go:10386 | PARTIAL | MsgBlock.Dispose() | .NET disposes only; Go flushes pending, clears cache, syncs fd, marks closed |

| fs.resetGlobalPerSubjectInfo() | filestore.go:10262 | MISSING | — | Clears and rebuilds global PSIM (per-subject index map) from all blocks | | fs.populateGlobalPerSubjectInfo(mb) | filestore.go:10360 | MISSING | — | Populates global PSIM from a single block's fss tree |

| fs.closeAllMsgBlocks(sync) | filestore.go:10426 | PORTED | FileStore.DisposeAllBlocks() | .NET iterates blocks and disposes; Go supports optional sync | | fs.Delete(inline) | filestore.go:10432 | PORTED | FileStore.Delete(bool) | .NET calls Stop + Directory.Delete; Go has more elaborate rename-then-remove, storage callback, purge directory handling | | fs.setSyncTimer() | filestore.go:10514 | MISSING | — | Periodic sync timer for dirty blocks; .NET has no equivalent background sync timer | | fs.cancelSyncTimer() | filestore.go:10527 | MISSING | — | Cancels the periodic sync timer |

| fullStateMagic / fullStateVersion | filestore.go:10537 | MISSING | — | Binary state file versioning constants | | fs.flushStreamStateLoop(qch, done) | filestore.go:10544 | PARTIAL | FileStore.WriteStreamStateAsync() | .NET has on-demand JSON state write; Go has a goroutine loop that periodically writes binary index.db | | timestampNormalized(t) | filestore.go:10574 | MISSING | — | Utility: returns UnixNano or 0 for zero time | | fs.writeFullState() | filestore.go:10583 | PARTIAL | FileStore.WriteStreamStateAsync() | .NET writes JSON snapshot; Go writes binary format with PSIM, per-block dmaps, block checksums, encryption, highway hash verification | | fs.forceWriteFullState() | filestore.go:10588 | PARTIAL | FileStore.WriteStreamStateAsync() | .NET has no force vs non-force distinction; Go skips if not dirty (non-forced) or too complex | | fs._writeFullState(force) | filestore.go:10599 | PARTIAL | FileStore.WriteStreamStateAsync() | .NET is a simplified JSON version; Go has full binary encoding with PSIM, block iteration, encryption, consistency checking | | fs.writeTTLState() | filestore.go:10833 | MISSING | — | Persists TTL tracking state to ttl.state file | | fs.writeMsgSchedulingState() | filestore.go:10847 | MISSING | — | Persists message scheduling state to disk |

| fs.Stop() | filestore.go:10862 | PORTED | FileStore.Stop() | .NET flushes active block and disposes; Go also writes full state, cancels timers, stops consumer stores, unregisters ATS | | fs.stop(delete, writeState) | filestore.go:10867 | PARTIAL | FileStore.Stop() / FileStore.Delete() | .NET has separate Stop/Delete; Go combines into one method with flags for delete and writeState |

| fs.streamSnapshot(w, includeConsumers, errCh) | filestore.go:10945 | MISSING | — | Streams tar+S2 snapshot through a pipe; .NET has StreamSnapshotService at a higher level but no block-level streaming snapshot | | fs.Snapshot(deadline, checkMsgs, includeConsumers) | filestore.go:11129 | MISSING | — | Creates SnapshotResult with pipe reader; .NET CreateSnapshotAsync in IStreamStore returns byte[] |

| fs.fileStoreConfig() | filestore.go:11171 | NOT_APPLICABLE | — | Simple getter under lock; .NET options are immutable | | fs.readLockAllMsgBlocks() | filestore.go:11179 | NOT_APPLICABLE | — | Go RWMutex pattern; .NET uses per-block RWLockSlim | | fs.readUnlockAllMsgBlocks() | filestore.go:11187 | NOT_APPLICABLE | — | Go RWMutex pattern; .NET uses per-block RWLockSlim |

| fs.EncodedStreamState(failed) | filestore.go:11194 | PARTIAL | FileStore.EncodedStreamState(ulong) | .NET returns empty array (stub); Go returns full binary encoding with deleted blocks | | fs.deleteBlocks() | filestore.go:11253 | MISSING | — | Returns DeleteBlocks (ranges + avl seqsets) representing interior deletes between and within blocks | | fs.deleteMap() | filestore.go:11293 | MISSING | — | Unions all block dmaps into a single SequenceSet | | fs.SyncDeleted(dbs) | filestore.go:11313 | MISSING | — | Synchronises deleted state from a peer's DeleteBlocks — used for NRG cluster replication |

| fs.ConsumerStore(name, created, cfg) | filestore.go:11379 | PARTIAL | FileStore.ConsumerStore(name, created, cfg) | .NET creates ConsumerFileStore with state file; Go also handles encryption key setup, meta file writing, cipher conversion, memory-storage override |

| o.convertCipher() | filestore.go:11511 | MISSING | — | Converts consumer state between ChaCha and AES ciphers | | o.kickFlusher() | filestore.go:11570 | PORTED | (implicit via _dirty flag + background flusher) | .NET uses periodic polling; Go uses channel-based kick | | o.setInFlusher() | filestore.go:11581 | PORTED | ConsumerFileStore.InFlusher property | | | o.clearInFlusher() | filestore.go:11588 | PORTED | ConsumerFileStore.RunFlusherAsync() finally block | | | o.inFlusher() | filestore.go:11595 | PORTED | ConsumerFileStore.InFlusher | | | o.flushLoop(fch, qch) | filestore.go:11602 | PORTED | ConsumerFileStore.RunFlusherAsync() | .NET uses Task.Delay polling; Go uses channel-based select with minTime throttle | | o.SetStarting(sseq) | filestore.go:11658 | PARTIAL | ConsumerFileStore.SetStarting(sseq) | .NET sets AckFloor only; Go also sets Delivered.Stream, AckFloor.Stream, encodes + writes to disk immediately | | o.UpdateStarting(sseq) | filestore.go:11671 | PARTIAL | ConsumerFileStore.UpdateStarting(sseq) | .NET sets AckFloor only; Go checks sseq > Delivered.Stream, handles AckNone policy, kicks flusher | | o.Reset(sseq) | filestore.go:11687 | PORTED | ConsumerFileStore.Reset(sseq) | | | o.HasState() | filestore.go:11695 | PARTIAL | ConsumerFileStore.HasState() | .NET checks in-memory only; Go also checks disk file existence | | o.UpdateDelivered(dseq, sseq, dc, ts) | filestore.go:11708 | PARTIAL | ConsumerFileStore.UpdateDelivered(...) | .NET has basic pending/redelivery tracking; Go has more nuanced handling: skips if dseq <= AckFloor, updates existing pending entries, respects MaxDeliver, stores dc-1 in redelivered | | o.UpdateAcks(dseq, sseq) | filestore.go:11777 | PARTIAL | ConsumerFileStore.UpdateAcks(dseq, sseq) | .NET has simplified ack floor advancement; Go handles AckAll policy separately, uses original dseq from pending, walks forward for floor advancement | | o.EncodedState() | filestore.go:11857 | PORTED | ConsumerFileStore.EncodedState() | | | o.encodeState() | filestore.go:11863 | PORTED | ConsumerStateCodec.Encode() | | | o.UpdateConfig(cfg) | filestore.go:11872 | MISSING | — | Updates consumer config and rewrites meta file | | o.Update(state) | filestore.go:11883 | PARTIAL | ConsumerFileStore.Update(state) | .NET does direct replacement; Go validates ranges, deep-copies pending/redelivered, checks for outdated updates | | o.encryptState(buf) | filestore.go:11932 | MISSING | — | AEAD encryption of consumer state | | dios semaphore + init() | filestore.go:11948 | NOT_APPLICABLE | — | Go disk I/O semaphore to limit OS thread blocking; .NET uses async I/O natively | | o.writeState(buf) | filestore.go:11969 | PARTIAL | ConsumerFileStore.FlushState() | .NET writes synchronously with File.WriteAllBytes; Go has encryption, writing flag, dios semaphore, atomic write | | o.updateConfig(cfg) | filestore.go:12005 | MISSING | — | Internal config update for ephemeral recovery | | o.writeConsumerMeta() | filestore.go:12014 | MISSING | — | Writes meta.json + meta.sum with optional encryption and key file | | checkConsumerHeader(hdr) | filestore.go:12070 | PORTED | ConsumerStateCodec.Decode() (inline check) | Magic byte and version check done inline in .NET decode | | o.copyPending() | filestore.go:12082 | PORTED | ConsumerFileStore.State() (inline copy) | Done inline in State() method | | o.copyRedelivered() | filestore.go:12090 | PORTED | ConsumerFileStore.State() (inline copy) | Done inline in State() method | | o.Type() | filestore.go:12099 | PORTED | ConsumerFileStore.Type() | | | o.State() | filestore.go:12103 | PORTED | ConsumerFileStore.State() | | | o.BorrowState() | filestore.go:12109 | PORTED | ConsumerFileStore.BorrowState() | | | o.stateWithCopy(doCopy) | filestore.go:12113 | PARTIAL | ConsumerFileStore.State() / BorrowState() | .NET always returns from memory; Go falls back to disk read with decryption | | o.stateWithCopyLocked(doCopy) | filestore.go:12120 | PARTIAL | ConsumerFileStore.State() / BorrowState() | .NET has no encrypted disk fallback | | o.loadState() | filestore.go:12203 | PORTED | ConsumerFileStore constructor | .NET loads state in constructor from disk | | decodeConsumerState(buf) | filestore.go:12216 | PORTED | ConsumerStateCodec.Decode() | Full Go wire format compatibility including v1 and v2 | | o.Stop() | filestore.go:12328 | PORTED | ConsumerFileStore.Stop() | | | o.waitOnFlusher() | filestore.go:12368 | PARTIAL | ConsumerFileStore.Stop() (Task.Wait) | .NET uses Task.Wait with timeout; Go polls with sleep | | o.Delete() | filestore.go:12383 | PORTED | ConsumerFileStore.Delete() | | | o.StreamDelete() | filestore.go:12387 | PORTED | ConsumerFileStore.StreamDelete() | | | o.delete(streamDeleted) | filestore.go:12391 | PARTIAL | ConsumerFileStore.Delete() | .NET always deletes file; Go skips dir removal if stream was already deleted |

| fs.AddConsumer(o) | filestore.go:12423 | MISSING | — | Registers a ConsumerStore with the fileStore's consumer list | | fs.RemoveConsumer(o) | filestore.go:12430 | MISSING | — | Removes a ConsumerStore from the fileStore's consumer list |

| CompressionInfo.MarshalMetadata() | filestore.go:12451 | MISSING | — | Encodes compression metadata header (algorithm + original size) | | CompressionInfo.UnmarshalMetadata(b) | filestore.go:12459 | MISSING | — | Decodes compression metadata header | | StoreCompression.Compress(buf) | filestore.go:12477 | PORTED | S2Codec.CompressWithTrailingChecksum() | .NET uses IronSnappy; Go uses S2 stream writer | | StoreCompression.Decompress(buf) | filestore.go:12517 | PORTED | S2Codec.DecompressWithTrailingChecksum() | .NET uses IronSnappy; Go uses S2 stream reader |

| fs.writeFileWithOptionalSync(name, data, perm) | filestore.go:12549 | PORTED | AtomicFileWriter.WriteAtomicallyAsync() | .NET uses temp-file + rename pattern; Go identical pattern + optional O_SYNC + dios semaphore | | writeFileWithSync(name, data, perm) | filestore.go:12553 | PARTIAL | AtomicFileWriter.WriteAtomicallyAsync() | .NET always async, no O_SYNC; Go forces sync | | writeAtomically(name, data, perm, sync) | filestore.go:12557 | PORTED | AtomicFileWriter.WriteAtomicallyAsync() | Core implementation ported; .NET lacks O_SYNC flag and directory fsync |

| validatePathExists(path, dir) | dirstore.go:40 | MISSING | — | Path validation utility | | validateDirPath(path) | dirstore.go:68 | MISSING | — | Directory path validation | | JWTChanged callback type | dirstore.go:73 | MISSING | — | Change notification delegate | | DirJWTStore struct | dirstore.go:77 | MISSING | — | JWT store with sharding, expiration, LRU | | newDir(dirPath, create) | dirstore.go:89 | MISSING | — | Directory creation helper | | NewImmutableDirJWTStore(...) | dirstore.go:110 | MISSING | — | Read-only JWT store factory | | NewDirJWTStore(...) | dirstore.go:121 | MISSING | — | Writable JWT store factory | | deleteType enum | dirstore.go:133 | MISSING | — | NoDelete / RenameDeleted / HardDelete | | NewExpiringDirJWTStore(...) | dirstore.go:150 | MISSING | — | JWT store with TTL, LRU eviction, limits | | store.IsReadOnly() | dirstore.go:193 | MISSING | — | | | store.LoadAcc(publicKey) | dirstore.go:197 | MISSING | — | Load account JWT | | store.SaveAcc(publicKey, jwt) | dirstore.go:201 | MISSING | — | Save account JWT | | store.LoadAct(hash) | dirstore.go:205 | MISSING | — | Load activation JWT | | store.SaveAct(hash, jwt) | dirstore.go:209 | MISSING | — | Save activation JWT | | store.Close() | dirstore.go:213 | MISSING | — | Close expiration tracker | | store.Pack(maxJWTs) | dirstore.go:223 | MISSING | — | Pack JWTs for replication | | store.PackWalk(maxJWTs, cb) | dirstore.go:267 | MISSING | — | Streaming pack with callback | | store.Merge(pack) | dirstore.go:318 | MISSING | — | Merge packed JWTs into store | | store.Reload() | dirstore.go:339 | MISSING | — | Reload JWTs from disk | | store.pathForKey(publicKey) | dirstore.go:377 | MISSING | — | Compute file path with optional sharding | | store.load(publicKey) | dirstore.go:395 | MISSING | — | Load JWT from disk | | store.write(path, publicKey, jwt) | dirstore.go:412 | MISSING | — | Write JWT with hash tracking, LRU eviction | | store.delete(publicKey) | dirstore.go:449 | MISSING | — | Delete JWT (rename or hard delete) | | store.save(publicKey, jwt) | dirstore.go:478 | MISSING | — | Save JWT with change callback | | store.saveIfNewer(publicKey, jwt) | dirstore.go:506 | MISSING | — | Save only if JWT is newer | | xorAssign(lVal, rVal) | dirstore.go:549 | MISSING | — | XOR hash helper | | store.Hash() | dirstore.go:556 | MISSING | — | Return XOR hash of all indexed JWTs | | jwtItem struct | dirstore.go:567 | MISSING | — | Priority queue item | | expirationTracker struct | dirstore.go:575 | MISSING | — | Heap + LRU + hash tracker | | expirationTracker heap methods | dirstore.go:587619 | MISSING | — | Len, Less, Swap, Push, Pop | | pq.updateTrack(publicKey) | dirstore.go:621 | MISSING | — | Update expiration + LRU position | | pq.unTrack(publicKey) | dirstore.go:635 | MISSING | — | Remove from tracker | | pq.track(publicKey, hash, jwt) | dirstore.go:643 | MISSING | — | Add/update tracking entry | | pq.close() | dirstore.go:672 | MISSING | — | Stop expiration goroutine | | store.startExpiring(...) | dirstore.go:680 | MISSING | — | Start background expiration ticker |

| Status | Count | | PORTED | 22 | | PARTIAL | 23 | | MISSING | 24 | | NOT_APPLICABLE | 4 | | Total | 73 |

| Status | Count | | PORTED | 0 | | PARTIAL | 0 | | MISSING | 33 | | NOT_APPLICABLE | 0 | | Total | 33 |

| Status | Count | | PORTED | 22 | | PARTIAL | 23 | | MISSING | 57 | | NOT_APPLICABLE | 4 | | Total | 106 |

| jetStreamCluster struct | :44-84 | PARTIAL | JetStreamMetaGroup in Cluster/JetStreamMetaGroup.cs | .NET has meta group tracking (streams map, inflight, peer management) but missing: streamResults/consumerResults subscriptions, stepdown/peerRemove/peerStreamMove/peerStreamCancelMove subscriptions, qch/stopped channels, lastMetaSnapTime/lastMetaSnapDuration monitoring fields | | inflightStreamInfo struct | :87-91 | PORTED | InflightInfo record in JetStreamMetaGroup.cs:1016 | Mapped to a record with OpsCount, Deleted, Assignment | | inflightConsumerInfo struct | :94-98 | PORTED | InflightInfo record in JetStreamMetaGroup.cs:1016 | Shared record type for both stream and consumer inflight | | peerRemoveInfo struct | :101-106 | MISSING | — | Peer-remove reply tracking for responding after quorum | | Placement struct | :109-113 | PORTED | PlacementPolicy in Cluster/PlacementEngine.cs:229-243 | .NET adds ExcludeTags and UniqueTag beyond Go's Cluster+Tags | | entryOp type + constants | :116-150 | PARTIAL | MetaEntryType enum in JetStreamMetaGroup.cs:967-990 | .NET has 7 values (StreamCreate, StreamDelete, ConsumerCreate, ConsumerDelete, PeerAdd, PeerRemove, Unknown). Missing granular stream ops: streamMsgOp, purgeStreamOp, deleteMsgOp, updateDeliveredOp, updateAcksOp, updateSkipOp, compressedStreamMsgOp, deleteRangeOp, batchMsgOp, batchCommitMsgOp, resetSeqOp, addPendingRequest, removePendingRequest | | raftGroup struct | :154-163 | PORTED | RaftGroup in Cluster/ClusterAssignmentTypes.cs:9-105 | Full port with Name, Peers, Storage, Cluster, Preferred, plus .NET-specific DesiredReplicas, QuorumSize, IsMember, SetPreferred, RemovePeer, AddPeer helpers | | streamAssignment struct | :166-184 | PORTED | StreamAssignment in ClusterAssignmentTypes.cs:111-139 | Core fields ported. Missing: Client, Restore, err, unsupported, resetting fields | | unsupportedStreamAssignment struct | :186-247 | MISSING | — | Entire unsupported stream assignment subsystem (info sub, handler) | | consumerAssignment struct | :250-266 | PORTED | ConsumerAssignment in ClusterAssignmentTypes.cs:145-164 | Core fields ported. Missing: Client, State, err, unsupported fields | | unsupportedConsumerAssignment struct | :268-330 | MISSING | — | Entire unsupported consumer assignment subsystem | | writeableConsumerAssignment struct | :332-340 | MISSING | — | Serialization DTO for consumer assignments in snapshots | | streamPurge struct | :343-350 | MISSING | — | Replicated purge operation struct | | streamMsgDelete struct | :353-360 | MISSING | — | Replicated message delete operation struct | | Constants (defaultStoreDirName, etc.) | :362-367 | PARTIAL | — | No explicit constants in .NET; defaultMetaGroupName logic is embedded |

| trackedJetStreamServers() | :370-385 | MISSING | — | Mixed-mode node counting | | getJetStreamCluster() | :387-399 | MISSING | — | Server-level accessor for JS cluster state | | JetStreamIsClustered() | :401-403 | MISSING | — | Atomic boolean check | | JetStreamIsLeader() | :405-407 | PARTIAL | JetStreamMetaGroup.IsLeader() | .NET has equivalent on meta group, not on Server | | JetStreamIsCurrent() | :409-428 | MISSING | — | Meta RAFT currency check | | JetStreamSnapshotMeta() | :430-451 | MISSING | — | Force meta snapshot | | JetStreamStepdownStream() | :453-477 | PARTIAL | ClusterControlApiHandlers.HandleStreamLeaderStepdown() | .NET has API handler stub but missing actual RAFT node interaction | | JetStreamStepdownConsumer() | :479-508 | PARTIAL | ClusterControlApiHandlers.HandleConsumerLeaderStepdown() | .NET has API handler stub but missing actual RAFT node interaction | | JetStreamSnapshotStream() | :510-539 | MISSING | — | Force stream-level snapshot | | JetStreamClusterPeers() | :541-568 | MISSING | — | Returns online JS peer names | | cc.isLeader() | :571-577 | PORTED | JetStreamMetaGroup.IsLeader() | Equivalent logic |

| cc.isStreamCurrent() | :582-618 | MISSING | — | Checks if stream is up-to-date via RAFT node + catchup state | | isStreamHealthy() | :622-679 | MISSING | — | Comprehensive stream health check (R1 check, node skew, monitor running, catching up, healthy) | | isConsumerHealthy() | :683-746 | MISSING | — | Comprehensive consumer health check | | subjectsOverlap() | :751-766 | MISSING | — | Cross-cluster subject overlap detection for stream assignments |

| getJetStreamFromAccount() | :768-784 | MISSING | — | Account-level JS accessor | | JetStreamIsStreamLeader() (Server) | :786-794 | MISSING | — | Server-level stream leader check | | JetStreamIsStreamLeader() (Account) | :796-804 | MISSING | — | Account-level stream leader check | | JetStreamIsStreamCurrent() | :806-814 | MISSING | — | Server-level stream currency check | | JetStreamIsConsumerLeader() (Account) | :816-824 | MISSING | — | Account-level consumer leader check | | JetStreamIsConsumerLeader() (Server) | :826-834 | MISSING | — | Server-level consumer leader check | | enableJetStreamClustering() | :836-862 | MISSING | — | Startup: validates cluster name, routes, calls setupMetaGroup | | isClustered() | :866-869 | MISSING | — | Lock-safe clustered check | | isClusteredNoLock() | :875-877 | MISSING | — | Lock-free atomic clustered check | | setupMetaGroup() | :879-993 | MISSING | — | Creates meta RAFT group: WAL, filestore, bootstrap, observer mode, starts monitorCluster | | getMetaGroup() | :995-1002 | MISSING | — | Returns meta RaftNode | | server() | :1004-1007 | NOT_APPLICABLE | — | Trivial getter |

| isLeaderless() | :1010-1026 | MISSING | — | Checks if meta group has no leader beyond lost-quorum interval | | isGroupLeaderless() | :1029-1071 | MISSING | — | Checks if a specific raft group is leaderless | | JetStreamIsStreamAssigned() | :1073-1086 | MISSING | — | Server-level stream assignment check | | streamAssigned() (jsAccount) | :1089-1101 | MISSING | — | Account-level stream assignment check | | cc.isStreamAssigned() | :1104-1121 | MISSING | — | Core stream assignment membership check |

| cc.isStreamLeader() | :1124-1154 | MISSING | — | Checks if this node is leader for a stream's raft group | | cc.isConsumerLeader() | :1157-1188 | MISSING | — | Checks if this node is leader for a consumer's raft group | | trackInflightStreamProposal() | :1193-1209 | PORTED | JetStreamMetaGroup.TrackInflightStreamProposal() | Full equivalent with ops counting | | removeInflightStreamProposal() | :1214-1229 | PORTED | JetStreamMetaGroup.RemoveInflightStreamProposal() | Full equivalent | | trackInflightConsumerProposal() | :1234-1255 | PORTED | JetStreamMetaGroup.TrackInflightConsumerProposal() | Full equivalent | | removeInflightConsumerProposal() | :1260-1280 | PORTED | JetStreamMetaGroup.RemoveInflightConsumerProposal() | Full equivalent |

| clusterQuitC() | :1283-1290 | MISSING | — | Returns cluster quit channel | | clusterStoppedC() | :1293-1300 | MISSING | — | Returns cluster stopped channel | | setMetaRecovering() | :1303-1310 | MISSING | — | Sets meta recovery state | | clearMetaRecovering() | :1313-1317 | MISSING | — | Clears meta recovery state | | isMetaRecovering() | :1320-1324 | MISSING | — | Checks meta recovery state | | recoveryUpdates struct | :1327-1333 | MISSING | — | Recovery-time diff tracking for streams/consumers | | ru.removeStream() | :1335-1342 | MISSING | — | Recovery diff: track stream removal | | ru.addStream() | :1344-1347 | MISSING | — | Recovery diff: track stream addition | | ru.updateStream() | :1349-1352 | MISSING | — | Recovery diff: track stream update | | ru.removeConsumer() | :1354-1364 | MISSING | — | Recovery diff: track consumer removal | | ru.addOrUpdateConsumer() | :1366-1373 | MISSING | — | Recovery diff: track consumer add/update |

| checkForOrphans() | :1378-1428 | MISSING | — | Post-recovery orphan stream/consumer cleanup | | getOrphans() | :1433-1453 | MISSING | — | Returns orphaned streams and consumers not in cluster assignments |

| monitorCluster() | :1455-1825 | PARTIAL | JetStreamClusterMonitor.StartAsync() in Cluster/JetStreamClusterMonitor.cs | .NET has basic channel-reading entry dispatch loop. Missing: compact/snapshot timer, leader check timer, health check timer, recovery state machine, snapshot scheduling (sync/async), leader change processing, cluster size checks, cold-boot mixed-mode adjustment |

| checkClusterSize() | :1828-1869 | MISSING | — | Adjusts cluster size for mixed-mode deployments | | writeableStreamAssignment struct | :1872-1879 | MISSING | — | Serialization DTO for snapshot encoding | | clusterStreamConfig() | :1881-1888 | MISSING | — | Returns stream config from cluster assignment | | metaSnapshot() | :1890-1895 | PARTIAL | MetaSnapshotCodec.Encode() | .NET has encoding but not the full js.metaSnapshot() wrapper | | applyMetaSnapshot() | :1897-2028 | PARTIAL | JetStreamClusterMonitor.ApplyMetaSnapshot() + JetStreamMetaGroup.ReplaceAllAssignments() | .NET has basic snapshot apply via ReplaceAllAssignments(). Missing: the full diff algorithm (saAdd/saDel/saChk), consumer delta processing, recovery-aware branching, orphan cleanup post-snapshot | | decodeMetaSnapshot() | :2031-2071 | PORTED | MetaSnapshotCodec.Decode() in Cluster/MetaSnapshotCodec.cs | S2-compressed JSON decode with version header | | encodeMetaSnapshot() | :2075-2143 | PORTED | MetaSnapshotCodec.Encode() in Cluster/MetaSnapshotCodec.cs | S2-compressed JSON encode with version header, metrics tracking not ported | | collectStreamAndConsumerChanges() | :2146-2237 | MISSING | — | Async snapshot pipeline: replay RAFT entries into assignment state machine |

| setStreamAssignmentRecovering() | :2241-2251 | MISSING | — | Marks stream assignment as recovering | | setConsumerAssignmentRecovering() | :2254-2263 | MISSING | — | Marks consumer assignment as recovering | | sa.copyGroup() | :2267-2272 | MISSING | — | Deep-copies stream assignment with group | | ca.copyGroup() | :2276-2281 | MISSING | — | Deep-copies consumer assignment with group | | sa.missingPeers() | :2284-2286 | PORTED | RaftGroup.IsUnderReplicated in ClusterAssignmentTypes.cs:36 | Property-based equivalent | | processAddPeer() | :2290-2339 | PORTED | JetStreamMetaGroup.ProcessAddPeer() in JetStreamMetaGroup.cs:790-819 | .NET adds new peer to under-replicated streams. Missing: cluster affinity check, consumer re-assignment proposals | | processRemovePeer() | :2342-2393 | PARTIAL | JetStreamMetaGroup.ProcessRemovePeer() in JetStreamMetaGroup.cs:827-841 | .NET removes from known peers and calls RemovePeerFromStream. Missing: self-removal advisory, DisableJetStream, consumer ephemeral cleanup | | removePeerFromStream() | :2396-2400 | PORTED | JetStreamMetaGroup.RemovePeerFromStream() in JetStreamMetaGroup.cs:849-862 | Equivalent logic | | removePeerFromStreamLocked() | :2403-2439 | PARTIAL | JetStreamMetaGroup.RemovePeerFromStream() | .NET has basic peer removal + remap. Missing: RAFT proposals for stream + consumer reassignment |

| hasPeerEntries() | :2442-2449 | MISSING | — | Checks if entries contain peer add/remove | | sa.recoveryKey() | :2453-2458 | MISSING | — | Recovery key generation for stream assignments | | ca.streamRecoveryKey() | :2460-2465 | MISSING | — | Recovery key for consumer's parent stream | | ca.recoveryKey() | :2467-2472 | MISSING | — | Recovery key generation for consumer assignments | | applyMetaEntries() | :2474-2608 | PARTIAL | JetStreamClusterMonitor.ApplyMetaEntry() in JetStreamClusterMonitor.cs:108-146 | .NET dispatches on JSON "Op" field. Go dispatches on binary entryOp byte. Missing: catchup entry handling, snapshot entry handling, peer add/remove entry handling, recovery-aware branching, peer-remove reply delivery |

| rg.isMember() | :2611-2621 | PORTED | RaftGroup.IsMember() in ClusterAssignmentTypes.cs:48 | Equivalent | | rg.setPreferred() | :2623-2656 | PARTIAL | RaftGroup.SetPreferred() in ClusterAssignmentTypes.cs:55-61 | .NET requires explicit peer ID. Go version auto-selects from online peers | | createRaftGroup() | :2659-2789 | MISSING | — | Full RAFT group creation: WAL setup, filestore/memstore, peer bootstrap, campaign, HA asset limits check | | mset.raftGroup() | :2792-2802 | NOT_APPLICABLE | — | Trivial accessor | | mset.raftNode() | :2804-2811 | NOT_APPLICABLE | — | Trivial accessor | | mset.removeNode() | :2813-2820 | MISSING | — | Deletes RAFT node from stream | | genPeerInfo() | :2824-2837 | MISSING | — | Helper for peer set splitting during migration |

| waitOnConsumerAssignments() | :2842-2892 | MISSING | — | Waits for consumer assignments before proceeding (interest retention) | | monitorStream() | :2895-3506 | PARTIAL | StreamReplicaGroup in Cluster/StreamReplicaGroup.cs | .NET has a simplified stream replica group model with election, propose, apply, snapshot. Missing: the full monitor loop (apply queue, leader change, compact timer, migration monitoring, direct access monitoring, interest state check, restore handling, scale-down logic, catchup error handling, resetClusteredState integration) |

| isMigrating() | :3509-3531 | MISSING | — | Detects stream migration (group peers != config replicas) | | resetClusteredState() | :3534-3637 | MISSING | — | Full clustered state reset: stepdown, delete/stop node, re-create stream + consumers | | isControlHdr() | :3639-3641 | NOT_APPLICABLE | — | Trivial header check |

| applyStreamEntries() | :3643-4000+ | PARTIAL | StreamReplicaGroup.ApplyCommittedEntriesAsync() in StreamReplicaGroup.cs:228-269 | .NET dispatches on string-based command prefixes (smsg:, centry:, +peer:, -peer:). Go dispatches on binary entryOp. Missing: full batchMsgOp/batchCommitMsgOp batch apply logic, deleteMsgOp with erase/remove, purgeStreamOp with request replay, EntrySnapshot with StreamReplicatedState, EntryRemovePeer processing, recovering-aware error handling, resetClusteredState on error |

| encodeAddStreamAssignment() | :8703+ (referenced) | PORTED | AssignmentCodec.EncodeStreamAssignment() in Cluster/AssignmentCodec.cs:52-53 | JSON serialization | | decodeStreamAssignment() | :8733+ (referenced) | PORTED | AssignmentCodec.DecodeStreamAssignment() in Cluster/AssignmentCodec.cs:61-74 | JSON deserialization | | encodeAddConsumerAssignment() | :9175+ (referenced) | PORTED | AssignmentCodec.EncodeConsumerAssignment() in Cluster/AssignmentCodec.cs:87-88 | JSON serialization | | decodeConsumerAssignment() | :9195+ (referenced) | PORTED | AssignmentCodec.DecodeConsumerAssignment() in Cluster/AssignmentCodec.cs:96-109 | JSON deserialization | | encodeAddConsumerAssignmentCompressed() | :9226+ (referenced) | PORTED | AssignmentCodec.CompressIfLarge() in Cluster/AssignmentCodec.cs:131-141 | Snappy compression with sentinel byte | | decodeConsumerAssignmentCompressed() | :9238+ (referenced) | PORTED | AssignmentCodec.DecompressIfNeeded() in Cluster/AssignmentCodec.cs:151-157 | Snappy decompression |

| selectPeerGroup() | :7212+ (referenced) | PORTED | PlacementEngine.SelectPeerGroup() in Cluster/PlacementEngine.cs:34-97 | Full pipeline: cluster affinity, tag filter, HA limit split, weighted score sort, unique-tag constraint | | remapStreamAssignment() | :7077+ (referenced) | PORTED | JetStreamMetaGroup.RemapStreamAssignment() in JetStreamMetaGroup.cs:872-904 | Replacement peer selection with fallback shrink |

| jsClusteredStreamRequest() | :7620+ (referenced) | PORTED | ClusteredRequestProcessor in Api/ClusteredRequestProcessor.cs | Channel-per-request pattern using TaskCompletionSource; register, wait, deliver, cancel-all |

| Status | Count | | PORTED | 25 | | PARTIAL | 14 | | MISSING | 48 | | NOT_APPLICABLE | 4 | | DEFERRED | 0 | | Total | 91 |

| stream.skipBatchIfRecovering | 4034-4066 | MISSING | -- | Batch recovery skip logic for stream RAFT apply; requires real RAFT + stream integration | | jetStream.applyStreamMsgOp | 4068-4242 | PARTIAL | StreamReplicaGroup.ApplyStreamMsgOp | .NET has simplified Store/Remove/Purge enum but lacks S2 decompression, flow-control reply, lastSeq mismatch retry, inflight/counter tracking, preAck clearing | | Server.replicas | 4246-4259 | MISSING | -- | Converts RAFT node peers to external PeerInfo with lag/active time | | jetStream.processStreamLeaderChange | 4262-4365 | PARTIAL | JetStreamMetaGroup.ProcessLeaderChange | .NET has leader change event + inflight clearing but no dedupe-ID clearing, inflight map clearing, advisory sending, stream setLeader, or API response to client | | stream.shouldSendLostQuorum | 4371-4379 | MISSING | -- | Throttled quorum-loss advisory gate | | Server.sendStreamLostQuorumAdvisory | 4381-4414 | MISSING | -- | Stream lost-quorum advisory publication | | Server.sendStreamLeaderElectAdvisory | 4416-4444 | MISSING | -- | Stream leader-elected advisory publication | | jetStream.streamAssignment (lookup) | 4448-4458 | PORTED | JetStreamMetaGroup.GetStreamAssignment | Direct lookup by account+stream | | jetStream.streamAssignmentOrInflight | 4462-4481 | PARTIAL | JetStreamMetaGroup.IsStreamInflight + GetStreamAssignment | Separate methods exist but no single combined lookup that returns the SA from inflight | | jetStream.streamAssignmentsOrInflightSeq | 4485-4507 | MISSING | -- | Iterator over all stream assignments (applied + inflight) for an account | | jetStream.streamAssignmentsOrInflightSeqAllAccounts | 4511-4538 | MISSING | -- | Iterator over all stream assignments across all accounts | | jetStream.processStreamAssignment | 4540-4647 | PARTIAL | JetStreamMetaGroup.ProcessStreamAssignment | .NET validates and adds assignment but lacks account lookup, stream creation dispatch, raft group node transfer, unsupported stream detection, syncSubject bug check | | jetStream.processUpdateStreamAssignment | 4650-4763 | PARTIAL | JetStreamMetaGroup.ProcessUpdateStreamAssignment | .NET updates config but lacks member check, raft node transfer, stream removal on non-member, unsupported handling | | Server.removeStream | 4767-4794 | MISSING | -- | Removes stream from non-member server (stepdown, node delete, monitor quit, stop) | | jetStream.processClusterUpdateStream | 4798-4940 | MISSING | -- | Full cluster stream update with scaling up/down, raft group creation, monitor start/stop, advisory response | | jetStream.processClusterCreateStream | 4944-5213 | MISSING | -- | Full cluster stream create with raft group, monitor goroutine, restore handling, single-replica path | | jetStream.processStreamRemoval | 5216-5264 | PARTIAL | JetStreamMetaGroup.ProcessStreamRemoval / JetStreamClusterMonitor.ProcessStreamRemoval | .NET removes assignment from meta state; lacks account lookup, created-time check, file cleanup | | jetStream.processClusterDeleteStream | 5266-5360 | MISSING | -- | Full stream deletion: raft node delete, monitor shutdown, file cleanup, response sending | | jetStream.processConsumerAssignment | 5362-5541 | PARTIAL | JetStreamMetaGroup.ProcessConsumerAssignment | .NET validates and adds to meta state; lacks member check, raft group transfer, state capture, unsupported handling, non-member removal with stepdown | | jetStream.processConsumerRemoval | 5543-5590 | PARTIAL | JetStreamMetaGroup.ProcessConsumerRemoval | .NET removes from meta state; lacks account lookup, created-time check, disk cleanup dispatch | | consumerAssignmentResult (struct) | 5592-5597 | MISSING | -- | Result struct for consumer assignment error forwarding | | jetStream.processClusterCreateConsumer | 5600-5854 | MISSING | -- | Full consumer create: raft group, add/update consumer, scale-down handling, monitor start, snapshot send, config update response | | jetStream.processClusterDeleteConsumer | 5856-5922 | MISSING | -- | Full consumer deletion: stop consumer, node delete, file cleanup, response | | jetStream.consumerAssignment (lookup) | 5926-5931 | PORTED | JetStreamMetaGroup.GetConsumerAssignment | Lookup by account/stream/consumer | | jetStream.consumerAssignmentOrInflight | 5935-5955 | PARTIAL | JetStreamMetaGroup.IsConsumerInflight + GetConsumerAssignment | Separate methods but no combined lookup returning the CA from inflight | | jetStream.consumerAssignmentsOrInflightSeq | 5959-5986 | MISSING | -- | Iterator over consumer assignments (applied + inflight) for account/stream | | jsAccount.consumerAssigned | 5989-5999 | MISSING | -- | Checks if this server has a consumer assigned | | jetStreamCluster.isConsumerAssigned | 6003-6025 | MISSING | -- | Checks consumer membership in cluster | | consumer.streamAndNode | 6028-6035 | NOT_APPLICABLE | -- | Go-specific accessor for consumer's stream + raft node | | consumer.replica | 6039-6049 | NOT_APPLICABLE | -- | Go-specific replica count getter | | consumer.raftGroup | 6051-6061 | NOT_APPLICABLE | -- | Go-specific raft group accessor | | consumer.clearRaftNode | 6063-6070 | NOT_APPLICABLE | -- | Go-specific raft node clear | | consumer.raftNode | 6072-6079 | NOT_APPLICABLE | -- | Go-specific raft node accessor | | jetStream.monitorConsumer | 6081-6349 | MISSING | -- | Consumer RAFT monitor loop: apply entries, leader change, snapshot, migration monitoring, compaction | | jetStream.applyConsumerEntries | 6351-6531 | PARTIAL | StreamReplicaGroup.ApplyConsumerEntry | .NET has simplified Ack/Nak/Deliver/Term/Progress enum tracking but lacks full op decoding (updateDeliveredOp, updateAcksOp, updateSkipOp, resetSeqOp, addPendingRequest, removePendingRequest), snapshot application, peer removal | | consumer.processReplicatedAck | 6535-6585 | MISSING | -- | Full replicated ack processing with AckAll gap handling, retention policy | | decodeAckUpdate | 6590-6600 | MISSING | -- | Binary uvarint decoder for ack updates | | decodeDeliveredUpdate | 6602-6620 | MISSING | -- | Binary uvarint/varint decoder for delivered updates | | jetStream.processConsumerLeaderChange | 6622-6698 | MISSING | -- | Consumer leader change: advisory, setLeader, API response, pause advisory | | consumer.shouldSendLostQuorum | 6701-6709 | MISSING | -- | Throttled consumer quorum-loss advisory gate | | Server.sendConsumerLostQuorumAdvisory | 6711-6745 | MISSING | -- | Consumer lost-quorum advisory publication | | Server.sendConsumerLeaderElectAdvisory | 6747-6777 | MISSING | -- | Consumer leader-elected advisory publication | | streamAssignmentResult (struct) | 6779-6785 | MISSING | -- | Result struct for stream assignment error forwarding | | isInsufficientResourcesErr | 6788-6790 | MISSING | -- | Error classification helper | | jetStream.processStreamAssignmentResults | 6794-6870 | MISSING | -- | Stream assignment error result processing with retry across clusters | | jetStream.processConsumerAssignmentResults | 6872-6906 | MISSING | -- | Consumer assignment error result processing | | streamAssignmentSubj / consumerAssignmentSubj (consts) | 6908-6911 | MISSING | -- | System subject constants for assignment results | | jetStream.startUpdatesSub | 6914-6937 | MISSING | -- | Subscribe to system subjects for assignment results, stepdown, peer remove, stream move | | jetStream.stopUpdatesSub | 6940-6970 | MISSING | -- | Unsubscribe from system subjects | | Server.sendDomainLeaderElectAdvisory | 6972-6999 | MISSING | -- | Domain leader-elected advisory publication | | jetStream.processLeaderChange (meta) | 7001-7074 | PARTIAL | JetStreamMetaGroup.ProcessLeaderChange | .NET clears inflight and fires event; lacks server atomic update, startUpdatesSub/stopUpdatesSub, observer stepdown, streamsCheck fix | | jetStreamCluster.remapStreamAssignment | 7077-7111 | PORTED | JetStreamMetaGroup.RemapStreamAssignment | .NET implements retain/replace/shrink logic | | selectPeerError (struct + methods) | 7113-7207 | MISSING | -- | Detailed peer-selection error reporting with tag/storage/offline reasons | | jetStreamCluster.selectPeerGroup | 7212-7507 | PARTIAL | PlacementEngine.SelectPeerGroup | .NET has tag filtering, cluster affinity, unique-tag, HA limit, weighted scoring; lacks per-peer storage availability check against MaxBytes, peerStreams/peerHA counting from live assignments, quorum check for online peers, detailed error reporting | | groupNameForStream | 7509-7511 | MISSING | -- | Stream raft group name generator with hash | | groupNameForConsumer | 7513-7515 | MISSING | -- | Consumer raft group name generator with hash | | groupName | 7517-7520 | MISSING | -- | Group name helper: prefix-R{n}{storage}-{hash} | | jetStream.tieredStreamAndReservationCount | 7524-7543 | MISSING | -- | Account-tier stream count + storage reservation tracking | | jetStream.createGroupForStream | 7547-7576 | MISSING | -- | Creates raft group for new stream with multi-cluster fallback | | Account.selectLimits | 7578-7596 | MISSING | -- | Selects account tier limits by replica count | | jetStream.jsClusteredStreamLimitsCheck | 7599-7618 | MISSING | -- | Pre-proposal stream limits validation (max streams, account limits) | | Server.jsClusteredStreamRequest | 7620-7701 | PARTIAL | ClusteredRequestProcessor | .NET has request-id correlation + timeout pattern; lacks full stream config validation, subject overlap check, placement + group creation, meta propose | | sysRequest[T] | 7710-7755 | MISSING | -- | Generic blocking system-account request utility | | Server.jsClusteredStreamUpdateRequest | 7757-8000+ | MISSING | -- | Full clustered stream update: config validation, move request handling, replica scaling, consumer remapping | | lostQuorumAdvInterval (const) | 4368 | MISSING | -- | 10-second throttle interval for quorum-loss advisories |

| Status | Count | | PORTED | 4 | | PARTIAL | 14 | | MISSING | 38 | | NOT_APPLICABLE | 5 | | Total | 61 |

| Cluster/JetStreamMetaGroup.cs | Meta-group assignment tracking, proposals, inflight, peer mgmt | | Cluster/StreamReplicaGroup.cs | Per-stream RAFT group model, propose/apply/stepdown, msg ops | | Cluster/PlacementEngine.cs | Topology-aware peer selection (selectPeerGroup) | | Cluster/ClusterAssignmentTypes.cs | RaftGroup, StreamAssignment, ConsumerAssignment types | | Cluster/AssignmentCodec.cs | JSON encode/decode for assignments, S2 compression | | Cluster/MetaSnapshotCodec.cs | Binary meta snapshot encode/decode | | Cluster/JetStreamClusterMonitor.cs | Background loop consuming RAFT entries, dispatching | | Cluster/AssetPlacementPlanner.cs | Simple replica count planning | | Api/Handlers/StreamApiHandlers.cs | Clustered stream create/update/delete handlers | | Api/Handlers/ConsumerApiHandlers.cs | Clustered consumer create/delete handlers | | Api/Handlers/ClusterControlApiHandlers.cs | Meta stepdown, stream/consumer leader stepdown | | Api/ClusteredRequestProcessor.cs | Pending request correlation (propose + wait) | | Snapshots/StreamSnapshotService.cs | TAR-based snapshot create/restore |

| jsClusteredStreamUpdateRequest (tail) | jetstream_cluster.go:7757 (80018138) | PARTIAL | StreamApiHandlers.HandleClusteredUpdateAsync | Go version handles scale up/down, move requests, peer set reassignment, consumer migration. .NET version only does simple config update via ProcessUpdateStreamAssignment. Missing: scale up/down logic, move request handling, consumer peer reassignment. | | jsClusteredStreamDeleteRequest | jetstream_cluster.go:81408165 | PORTED | StreamApiHandlers.HandleClusteredDeleteAsync | Proposes deletion to meta group, validates existence first. | | jsClusteredStreamPurgeRequest | jetstream_cluster.go:81688212 | PARTIAL | StreamApiHandlers.HandlePurge (local) | Go proposes purge through RAFT when clustered (stream group node). .NET has local purge only, no RAFT proposal path for purge. | | jsClusteredStreamRestoreRequest | jetstream_cluster.go:82148262 | PARTIAL | StreamApiHandlers.HandleRestore + StreamSnapshotService | Go creates a new RAFT group, sets preferred leader, proposes as stream assignment with Restore state. .NET has local restore path but no RAFT-based clustered restore proposal. | | allPeersOffline | jetstream_cluster.go:82658278 | MISSING | — | Server-level helper to check if all peers in a RAFT group are offline. No nodeToInfo equivalent in .NET. | | jsClusteredStreamListRequest | jetstream_cluster.go:82828444 | PARTIAL | JetStreamApiRouter routes to StreamApiHandlers.HandleList | Go does scatter-gather across cluster (sends internal msgs to each stream peer, collects responses, handles timeouts, offline peers, missing names). .NET has local-only list from StreamManager. | | jsClusteredConsumerListRequest | jetstream_cluster.go:84488591 | PARTIAL | JetStreamApiRouter routes to ConsumerApiHandlers.HandleList | Same scatter-gather pattern as stream list. .NET has local-only consumer list. | | encodeStreamPurge | jetstream_cluster.go:85938598 | MISSING | — | Binary encode of streamPurge for RAFT proposal. | | decodeStreamPurge | jetstream_cluster.go:86008604 | MISSING | — | Binary decode of streamPurge from RAFT log. | | jsClusteredConsumerDeleteRequest | jetstream_cluster.go:86068643 | PORTED | ConsumerApiHandlers.HandleClusteredDeleteAsync | Proposes consumer deletion via meta RAFT group. | | encodeMsgDelete | jetstream_cluster.go:86458650 | MISSING | — | Binary encode of streamMsgDelete for RAFT proposal. | | decodeMsgDelete | jetstream_cluster.go:86528656 | MISSING | — | Binary decode of streamMsgDelete from RAFT log. | | jsClusteredMsgDeleteRequest | jetstream_cluster.go:86588701 | MISSING | — | Clustered message delete by sequence — proposes through stream RAFT node. No .NET equivalent. | | encodeAddStreamAssignment | jetstream_cluster.go:87038711 | PORTED | AssignmentCodec.EncodeStreamAssignment | JSON serialization of stream assignment. | | encodeUpdateStreamAssignment | jetstream_cluster.go:87138721 | PARTIAL | AssignmentCodec.EncodeStreamAssignment | Go uses a separate opcode byte (updateStreamOp). .NET uses same encoder without op-code prefix. | | encodeDeleteStreamAssignment | jetstream_cluster.go:87238731 | PARTIAL | AssignmentCodec.EncodeStreamAssignment | Go uses removeStreamOp opcode byte. .NET lacks op-code prefix differentiation. | | decodeStreamAssignment | jetstream_cluster.go:87338742 | PORTED | AssignmentCodec.DecodeStreamAssignment | JSON deserialization of stream assignment. | | decodeStreamAssignmentConfig | jetstream_cluster.go:87448764 | PARTIAL | AssignmentCodec.DecodeStreamAssignment | Go does DisallowUnknownFields for forward-compat (marks as unsupported). .NET does basic decode without unsupported field detection. | | encodeDeleteRange | jetstream_cluster.go:87668771 | MISSING | — | Binary encode of DeleteRange for catchup gap markers. | | decodeDeleteRange | jetstream_cluster.go:87738780 | MISSING | — | Binary decode of DeleteRange. | | createGroupForConsumer | jetstream_cluster.go:87838821 | PARTIAL | PlacementEngine.SelectPeerGroup | Go selects peers from stream's group, checks active/offline, enforces quorum, picks storage type. .NET PlacementEngine does general peer selection but not the specific consumer-from-stream-peers logic. | | jsClusteredConsumerRequest | jetstream_cluster.go:88249173 | PARTIAL | ConsumerApiHandlers.HandleClusteredCreateAsync | Go has full validation: account limits, maxConsumers check, WQ policy checks, ephemeral naming, HA asset limits, scale up/down, consumer state transfer. .NET does basic leader + stream-exists validation only. | | encodeAddConsumerAssignment | jetstream_cluster.go:91759183 | PORTED | AssignmentCodec.EncodeConsumerAssignment | JSON serialization of consumer assignment. | | encodeDeleteConsumerAssignment | jetstream_cluster.go:91859193 | PARTIAL | AssignmentCodec.EncodeConsumerAssignment | Go uses removeConsumerOp opcode. .NET lacks op-code differentiation. | | decodeConsumerAssignment | jetstream_cluster.go:91959204 | PORTED | AssignmentCodec.DecodeConsumerAssignment | JSON deserialization of consumer assignment. | | decodeConsumerAssignmentConfig | jetstream_cluster.go:92069224 | PARTIAL | AssignmentCodec.DecodeConsumerAssignment | Go does unsupported-field detection + API level check. .NET does basic decode. | | encodeAddConsumerAssignmentCompressed | jetstream_cluster.go:92269236 | PORTED | AssignmentCodec.CompressIfLarge | S2/Snappy compression for large consumer assignments. | | decodeConsumerAssignmentCompressed | jetstream_cluster.go:92389250 | PORTED | AssignmentCodec.DecompressIfNeeded | Snappy decompression for compressed consumer assignments. | | decodeStreamMsg | jetstream_cluster.go:92549309 | MISSING | — | Binary wire decode of replicated stream messages (seq, ts, subject, reply, hdr, msg, flags). Critical for RAFT replication. | | decodeBatchMsg | jetstream_cluster.go:93119332 | MISSING | — | Binary decode of batch message wrapper (batchId, batchSeq, inner op). | | encodeStreamMsg | jetstream_cluster.go:93399341 | MISSING | — | Binary wire encode of replicated stream messages. | | encodeStreamMsgAllowCompress | jetstream_cluster.go:93439345 | MISSING | — | Wrapper calling encode with compression allowed. | | encodeStreamMsgAllowCompressAndBatch | jetstream_cluster.go:93529421 | MISSING | — | Full binary encoder with S2 compression (threshold 8KB), batch support, source/mirror flags. Core of clustered message replication. | | compressThreshold (const) | jetstream_cluster.go:9349 | MISSING | — | 8192-byte threshold for message compression. | | msgFlagFromSourceOrMirror (const) | jetstream_cluster.go:9336 | MISSING | — | Flag constant for source/mirror tracking. | | supportsBinarySnapshot | jetstream_cluster.go:94249428 | MISSING | — | Checks if all peers support binary snapshot format. | | supportsBinarySnapshotLocked | jetstream_cluster.go:94329450 | MISSING | — | Lock-held version checking peer nodeInfo for binary snapshot support. | | streamSnapshot (struct) | jetstream_cluster.go:94549461 | MISSING | — | Legacy JSON snapshot type (v1 format with deleted[]uint64). | | stateSnapshot | jetstream_cluster.go:94649468 | MISSING | — | Creates binary/legacy snapshot for RAFT. .NET has StreamSnapshotService but it's TAR-based, not the RAFT binary snapshot format. | | stateSnapshotLocked | jetstream_cluster.go:94729501 | MISSING | — | Lock-held snapshot with binary vs legacy fallback and EncodedStreamState. | | processClusteredInboundMsg | jetstream_cluster.go:95079690 | MISSING | — | Proposes inbound published message to stream RAFT group. Core of clustered publish path: leader check, sealed check, limits, dedup, lag warning, message trace. | | streamLagWarnThreshold (const) | jetstream_cluster.go:9504 | MISSING | — | 10,000 threshold for lag warning. | | getAndDeleteMsgTrace | jetstream_cluster.go:96929703 | MISSING | — | Retrieves and deletes a message trace by sequence. | | streamSyncRequest (struct) | jetstream_cluster.go:97079713 | MISSING | — | Request structure for stream catchup (Peer, FirstSeq, LastSeq, DeleteRangesOk, MinApplied). | | calculateSyncRequest | jetstream_cluster.go:97179728 | MISSING | — | Calculates catchup request based on local state vs snapshot. | | processSnapshotDeletes | jetstream_cluster.go:97329756 | MISSING | — | Processes deletes from snapshot (Compact, SyncDeleted). | | setCatchupPeer | jetstream_cluster.go:97589768 | MISSING | — | Sets catchup peer with lag tracking. | | updateCatchupPeer | jetstream_cluster.go:97719780 | MISSING | — | Decrements catchup lag by one. | | decrementCatchupPeer | jetstream_cluster.go:97829796 | MISSING | — | Decrements catchup lag by N. | | clearCatchupPeer | jetstream_cluster.go:97989804 | MISSING | — | Clears a single catchup peer. | | clearAllCatchupPeers | jetstream_cluster.go:98079811 | MISSING | — | Clears all catchup peers. | | lagForCatchupPeer | jetstream_cluster.go:98139820 | MISSING | — | Returns lag for a specific catchup peer. | | hasCatchupPeers | jetstream_cluster.go:98229826 | MISSING | — | Returns true if any catchup peers exist. | | setCatchingUp | jetstream_cluster.go:98289830 | MISSING | — | Atomic bool: set catching up. | | clearCatchingUp | jetstream_cluster.go:98329834 | MISSING | — | Atomic bool: clear catching up. | | isCatchingUp | jetstream_cluster.go:98369838 | MISSING | — | Atomic bool: is catching up. | | isCurrent | jetstream_cluster.go:98429847 | MISSING | — | Check if non-leader stream is current (RAFT current + not catching up). | | maxConcurrentSyncRequests (const) | jetstream_cluster.go:9850 | MISSING | — | 32 max concurrent sync requests. | | Error sentinel vars (catchup errors) | jetstream_cluster.go:98529860 | MISSING | — | errCatchupCorruptSnapshot, errCatchupStalled, errCatchupStreamStopped, etc. | | processSnapshot | jetstream_cluster.go:986310000+ | MISSING | — | Full stream snapshot processing: delete sync, calculate sync request, pause RAFT apply, semaphore-limited catchup with retries (max 3). ~140 lines. | | processCatchupMsg | jetstream_cluster.go:1016010251 | MISSING | — | Processes out-of-band catchup messages: deleteRange handling, S2 decompression, preAck clearing, store writes, dedup tracking. | | flushAllPending | jetstream_cluster.go:1025410256 | MISSING | — | Flush pending writes after snapshot install. | | handleClusterSyncRequest | jetstream_cluster.go:1025810265 | MISSING | — | Handler for inbound cluster sync requests; starts runCatchup goroutine. | | offlineClusterInfo | jetstream_cluster.go:1026810280 | MISSING | — | Returns ClusterInfo for offline RAFT group (all replicas marked offline). | | clusterInfo | jetstream_cluster.go:1028310355 | MISSING | — | Returns full ClusterInfo for RAFT group: leader, replicas, lag, current status, sorted by name. Central to /jsz and stream info responses. | | checkClusterInfo | jetstream_cluster.go:1035710365 | MISSING | — | Adjusts ClusterInfo replicas for catchup lag. | | streamAlternates | jetstream_cluster.go:1037010420 | MISSING | — | Returns ranked list of stream mirrors/alternates for client connection. | | handleClusterStreamInfoRequest | jetstream_cluster.go:1042310425 | MISSING | — | Inbound handler for cluster stream info (dispatches to processClusterStreamInfoRequest). | | processClusterStreamInfoRequest | jetstream_cluster.go:1042710460 | MISSING | — | Processes cluster stream info request: gathers state, config, cluster info, sources, mirror. | | defaultMaxTotalCatchupOutBytes (const) | jetstream_cluster.go:10465 | MISSING | — | 64 MB max total server-wide catchup outbound bytes. | | gcbTotal | jetstream_cluster.go:1046810472 | MISSING | — | Returns total outstanding catchup bytes. | | gcbBelowMax | jetstream_cluster.go:1047610480 | MISSING | — | Returns true if catchup bytes below max. | | gcbAdd | jetstream_cluster.go:1048510493 | MISSING | — | Adds to server-wide and local catchup byte counters. | | gcbSubLocked | jetstream_cluster.go:1049910509 | MISSING | — | Subtracts from catchup byte counters (locked). | | gcbSub | jetstream_cluster.go:1051210516 | MISSING | — | Locking wrapper for gcbSubLocked. | | gcbSubLast | jetstream_cluster.go:1052210527 | MISSING | — | Final subtract + zero out local counter on catchup exit. | | cbKickChan | jetstream_cluster.go:1053010534 | MISSING | — | Returns kick channel for catchup bandwidth management. | | runCatchup | jetstream_cluster.go:1053610846 | MISSING | — | Leader-side catchup sender: flow control, batch sending, ack tracking, delete ranges, gap markers, activity timeout, global bandwidth cap. ~310 lines. | | syncSubjForStream | jetstream_cluster.go:1085010852 | MISSING | — | Returns sync subject for stream catchup. | | syncReplySubject | jetstream_cluster.go:1085410856 | MISSING | — | Returns reply subject for sync. | | infoReplySubject | jetstream_cluster.go:1085810860 | MISSING | — | Returns reply subject for info. | | syncAckSubject | jetstream_cluster.go:1086210864 | MISSING | — | Returns ack subject for sync flow control. | | syncSubject | jetstream_cluster.go:1086610880 | MISSING | — | Generates random sync subject with base encoding. | | clusterStreamInfoT (const) | jetstream_cluster.go:10883 | MISSING | — | Subject template for cluster stream info requests. | | clusterConsumerInfoT (const) | jetstream_cluster.go:10884 | MISSING | — | Subject template for cluster consumer info requests. | | jsaUpdatesSubT / jsaUpdatesPubT (consts) | jetstream_cluster.go:1088510886 | MISSING | — | Subject templates for JSC account-related update subscriptions. | | jscAllSubj (const) | jetstream_cluster.go:10848 | MISSING | — | $JSC.> wildcard subscription for all cluster subjects. |

| Status | Count | | PORTED | 8 | | PARTIAL | 13 | | MISSING | 56 | | NOT_APPLICABLE | 0 | | DEFERRED | 0 | | Total | 77 |

Change Log

Date Change By
2026-02-25 JS-2a: store.go full + stream.go lines 1-4000. 172 symbols. PORTED:55 PARTIAL:30 MISSING:75 NA:12 opus
2026-02-25 JS-2b: stream.go lines 4001-end. 116 symbols. PORTED:11 PARTIAL:24 MISSING:73 NA:8 opus
2026-02-25 JS-3a: consumer.go lines 1-3500. 115 symbols. PORTED:23 PARTIAL:21 MISSING:70 NA:1 opus
2026-02-25 JS-3b: consumer.go lines 3501-end. 105 symbols. PORTED:31 PARTIAL:28 MISSING:37 NA:9 opus
2026-02-25 JS-4a: memstore + filestore 1-4000. 140 symbols. PORTED:37 PARTIAL:27 MISSING:71 NA:5 opus
2026-02-25 JS-4b: filestore 4001-7000. 80 symbols. PORTED:14 PARTIAL:27 MISSING:37 NA:2 opus
2026-02-25 JS-4c: filestore 7001-10000. 82 symbols. PORTED:26 PARTIAL:19 MISSING:32 NA:5 opus
2026-02-25 JS-4d: filestore 10001-end + dirstore. 106 symbols. PORTED:22 PARTIAL:23 MISSING:57 NA:4 opus
2026-02-25 JS-5a: jetstream_cluster.go lines 1-4000. 91 symbols. PORTED:25 PARTIAL:14 MISSING:48 NA:4 opus
2026-02-25 JS-5b: jetstream_cluster.go lines 4001-8000. 61 symbols. PORTED:4 PARTIAL:14 MISSING:38 NA:5 opus
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