Files
natsnet/docs/plans/phases/phase-6-porting.md
Joseph Doherty 8d68f63e6c chore: update project structure, naming, and add reporting infrastructure
- Update all 7 phase docs with source/target location references
  (golang/ for Go source, dotnet/ for .NET version)
- Rename NATS.Server to ZB.MOM.NatsNet.Server in phase 4-7 docs
- Update solution layout to dotnet/src/ and dotnet/tests/ structure
- Create CLAUDE.md with project summary and phase links
- Update .gitignore: track porting.db, add standard .NET patterns
- Add golang/nats-server as git submodule
- Add reports/generate-report.sh and pre-commit hook
- Add documentation_rules.md to version control
2026-02-26 06:38:56 -05:00

9.2 KiB

Phase 6: Initial Porting

Port Go code to .NET 10 C#, working through the dependency graph bottom-up. This is the main implementation phase where the actual code is written.

Objective

Implement every non-N/A module, feature, and test in the porting database. Work from leaf nodes (items with no unported dependencies) upward through the dependency graph. Keep the database current as work progresses.

Prerequisites

  • Phase 5 complete: all mappings verified, no collisions, naming validated
  • .NET solution structure created:
    • dotnet/src/ZB.MOM.NatsNet.Server/ZB.MOM.NatsNet.Server.csproj
    • dotnet/src/ZB.MOM.NatsNet.Server.Host/ZB.MOM.NatsNet.Server.Host.csproj
    • dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ZB.MOM.NatsNet.Server.Tests.csproj
    • dotnet/tests/ZB.MOM.NatsNet.Server.IntegrationTests/ZB.MOM.NatsNet.Server.IntegrationTests.csproj
  • Library dependencies (NuGet packages) added per Phase 3 mappings
  • Verify readiness: dotnet run --project tools/NatsNet.PortTracker -- phase check 5 --db porting.db

Source and Target Locations

  • Go source code is located in the golang/ folder (specifically golang/nats-server/)
  • .NET ported version is located in the dotnet/ folder

Porting Workflow

This is the core loop. Repeat until all items are complete.

Step 1: Find ready items

Query for items whose dependencies are all ported (status complete, verified, or n_a):

dotnet run --project tools/NatsNet.PortTracker -- dependency ready --db porting.db

This returns modules and features that have no unported dependencies. Start with these.

Step 2: Pick an item and mark as stub

Choose an item from the ready list. Mark it as stub to signal work has begun:

dotnet run --project tools/NatsNet.PortTracker -- feature update <id> --status stub --db porting.db

Step 3: Create the skeleton

In the .NET project, create the class and method skeleton based on the mapping:

  1. Look up the mapping: dotnet run --project tools/NatsNet.PortTracker -- feature show <id> --db porting.db
  2. Create the file at the correct path under dotnet/src/ZB.MOM.NatsNet.Server/ following the namespace hierarchy
  3. Add the class declaration, method signature, and a throw new NotImplementedException() body

For batch scaffolding of an entire module:

dotnet run --project tools/NatsNet.PortTracker -- feature update 0 --status stub \
  --all-in-module <module_id> --db porting.db

Step 4: Implement the logic

Reference the Go source code. The database stores the Go file path and line number for each feature:

dotnet run --project tools/NatsNet.PortTracker -- feature show <id> --db porting.db

The output includes Go File, Go Line, and Go LOC fields. Open the Go source at those coordinates and translate the logic to C#.

Key translation patterns:

Go pattern .NET equivalent
goroutine + channel Task + Channel<T> or async/await
sync.Mutex lock statement or SemaphoreSlim
sync.RWMutex ReaderWriterLockSlim
sync.WaitGroup Task.WhenAll or CountdownEvent
defer try/finally or using/IDisposable
interface{} / any object or generics
[]byte byte[], ReadOnlySpan<byte>, or ReadOnlyMemory<byte>
map[K]V Dictionary<K,V> or ConcurrentDictionary<K,V>
error return Exceptions or Result<T> pattern
panic/recover Exceptions (avoid Environment.FailFast for recoverable cases)
select on channels Task.WhenAny or Channel<T> reader patterns
context.Context CancellationToken
io.Reader/Writer Stream, PipeReader/PipeWriter

Step 5: Mark complete

Once the implementation compiles and the basic logic is in place:

dotnet run --project tools/NatsNet.PortTracker -- feature update <id> --status complete --db porting.db

Step 6: Run targeted tests

If tests exist for this feature, run them:

dotnet test --filter "FullyQualifiedName~ZB.MOM.NatsNet.Server.Tests.Protocol" \
  dotnet/tests/ZB.MOM.NatsNet.Server.Tests/

Fix any failures before moving on.

Step 7: Check what is now unblocked

Completing items may unblock others that depend on them:

dotnet run --project tools/NatsNet.PortTracker -- dependency ready --db porting.db

Return to Step 2 with the newly available items.

DB Update Discipline

The porting database must stay current. Update status at every transition:

# Starting work on a feature
dotnet run --project tools/NatsNet.PortTracker -- feature update 42 --status stub --db porting.db

# Feature implemented
dotnet run --project tools/NatsNet.PortTracker -- feature update 42 --status complete --db porting.db

# Batch scaffolding for all features in a module
dotnet run --project tools/NatsNet.PortTracker -- feature update 0 --status stub \
  --all-in-module 3 --db porting.db

# Module fully ported (all its features are complete)
dotnet run --project tools/NatsNet.PortTracker -- module update 3 --status complete --db porting.db

# Check progress
dotnet run --project tools/NatsNet.PortTracker -- report summary --db porting.db

Status transitions follow this progression:

not_started -> stub -> complete -> verified (Phase 7)
                  \-> n_a (if determined during porting)

Never skip stub -- it signals that work is in progress and prevents duplicate effort.

Porting Order Strategy

Start with leaf modules

Leaf modules have no dependencies on other unported modules. They are safe to port first because nothing they call is missing.

# These are the leaves — port them first
dotnet run --project tools/NatsNet.PortTracker -- dependency ready --db porting.db

Typical leaf modules include:

  • Utility/helper code (string manipulation, byte buffer pools)
  • Constants and enums
  • Configuration types (options, settings)
  • Error types and codes

Then work upward

After leaves are done, modules that depended only on those leaves become ready. Continue up the dependency graph:

Leaf utilities -> Protocol types -> Parser -> Connection handler -> Server

Port tests alongside features

When porting a feature, also port its associated tests in the same pass. This provides immediate validation:

# List tests for a feature
dotnet run --project tools/NatsNet.PortTracker -- test list --module <module_id> --db porting.db

# After porting a test
dotnet run --project tools/NatsNet.PortTracker -- test update <id> --status complete --db porting.db

Progress Tracking

Check overall progress regularly:

# Summary stats
dotnet run --project tools/NatsNet.PortTracker -- report summary --db porting.db

# What is still blocked
dotnet run --project tools/NatsNet.PortTracker -- dependency blocked --db porting.db

# Phase-level check
dotnet run --project tools/NatsNet.PortTracker -- phase check 6 --db porting.db

Handling Discoveries During Porting

During implementation, you may find:

Items that should be N/A

If a feature turns out to be unnecessary in .NET (discovered during implementation):

dotnet run --project tools/NatsNet.PortTracker -- feature set-na <id> \
  --reason "Go-specific memory management, handled by .NET GC" --db porting.db

Missing dependencies

If the Go analyzer missed a dependency:

# The dependency is tracked in the DB via the dependencies table
# For now, just ensure the target is ported before continuing
dotnet run --project tools/NatsNet.PortTracker -- dependency show feature <id> --db porting.db

Design changes

If the .NET design needs to differ from the original mapping (e.g., splitting a large Go function into multiple .NET methods), update the mapping:

dotnet run --project tools/NatsNet.PortTracker -- feature map <id> \
  --class "NewClassName" \
  --method "NewMethodName" \
  --db porting.db

Tips

  1. Keep the build green. The solution should compile after each feature is completed. Do not leave unresolved references.
  2. Write idiomatic C#. Do not transliterate Go line-by-line. Use .NET patterns (async/await, LINQ, Span, dependency injection) where they produce cleaner code.
  3. Use CancellationToken everywhere. The Go code uses context.Context pervasively -- mirror this with CancellationToken parameters.
  4. Prefer ReadOnlySpan<byte> for hot paths. The NATS parser processes bytes at high throughput. Use spans and avoid allocations in the critical path.
  5. Do not port Go comments verbatim. Translate the intent into C# XML doc comments where appropriate.
  6. Run dotnet build frequently. Catch compile errors early rather than accumulating them.

Completion Criteria

  • All non-N/A modules have status complete or better
  • All non-N/A features have status complete or better
  • All non-N/A tests have status complete or better
  • The solution compiles without errors: dotnet build
  • dependency blocked returns no items (or only items waiting for Phase 7 verification)
  • report summary shows the expected completion counts