docs: add phase 1-3 instruction guides

This commit is contained in:
Joseph Doherty
2026-02-26 06:22:21 -05:00
parent cecbb49653
commit 1bc64cf36e
3 changed files with 889 additions and 0 deletions

View File

@@ -0,0 +1,291 @@
# Phase 1: Go Codebase Decomposition
## Objective
Parse the Go NATS server source code into a structured SQLite database, extracting
modules, features (functions/methods), unit tests, external library imports, and
inter-module dependencies. This database becomes the single source of truth that
drives all subsequent porting phases.
## Prerequisites
| Requirement | Version / Notes |
|---|---|
| Go | 1.25+ (required by `tools/go-analyzer/go.mod`) |
| .NET SDK | 10.0+ |
| SQLite3 CLI | 3.x (optional, for manual inspection) |
| CGO | Must be enabled (`CGO_ENABLED=1`); the Go analyzer uses `github.com/mattn/go-sqlite3` |
| Go source | Cloned at `golang/nats-server/` relative to the repo root |
Verify prerequisites before starting:
```bash
go version # should print go1.25 or later
dotnet --version # should print 10.x
sqlite3 --version # optional, any 3.x
echo $CGO_ENABLED # should print 1 (or be unset; we set it explicitly below)
```
## Steps
### Step 1: Initialize the porting database
Create a fresh SQLite database with the porting tracker schema. This creates
`porting.db` in the repository root with all tables, indexes, and triggers.
```bash
dotnet run --project tools/NatsNet.PortTracker -- init --db porting.db --schema porting-schema.sql
```
Expected output:
```
Database initialized at porting.db
```
If the database already exists, this command is idempotent -- it applies
`CREATE TABLE IF NOT EXISTS` statements and will not destroy existing data.
### Step 2: Build the Go analyzer
The Go analyzer is a standalone tool that uses `go/ast` to parse Go source files
and writes results directly into the SQLite database.
```bash
cd tools/go-analyzer && CGO_ENABLED=1 go build -o go-analyzer . && cd ../..
```
This produces the binary `tools/go-analyzer/go-analyzer`. If the build fails,
see the Troubleshooting section below.
### Step 3: Run the Go analyzer
Point the analyzer at the NATS server source and the porting database:
```bash
./tools/go-analyzer/go-analyzer \
--source golang/nats-server \
--db porting.db \
--schema porting-schema.sql
```
Expected output (counts will vary with the NATS server version):
```
Analysis complete:
Modules: <N>
Features: <N>
Unit Tests: <N>
Dependencies: <N>
Imports: <N>
```
The analyzer does the following:
1. Walks `golang/nats-server/server/` for all `.go` files (skipping `configs/`
and `testdata/` directories).
2. Groups files into logical modules by directory.
3. Parses each non-test file, extracting every `func` and method as a feature.
4. Parses each `_test.go` file, extracting `Test*` and `Benchmark*` functions.
5. Infers module-level dependencies from cross-package imports.
6. Collects all import paths and classifies them as stdlib or external.
7. Writes modules, features, unit_tests, dependencies, and library_mappings to
the database.
### Step 4: Review module groupings
List all modules that were created to confirm the grouping makes sense:
```bash
dotnet run --project tools/NatsNet.PortTracker -- module list --db porting.db
```
This shows every module with its ID, name, status, Go package, and line count.
Verify that the major areas of the NATS server are represented (e.g., core,
jetstream, client, auth, protocol, route, gateway, leafnode, mqtt, websocket,
monitoring, logging, errors, subscriptions, tls, events, raft, config, accounts).
### Step 5: Spot-check individual modules
Inspect a few modules to verify that features and tests were correctly extracted:
```bash
# Check the first module
dotnet run --project tools/NatsNet.PortTracker -- module show 1 --db porting.db
# Check a few more
dotnet run --project tools/NatsNet.PortTracker -- module show 2 --db porting.db
dotnet run --project tools/NatsNet.PortTracker -- module show 3 --db porting.db
```
For each module, confirm that:
- Features list functions and methods from the corresponding Go files.
- Each feature has a `go_file`, `go_method`, and `go_line_number`.
- Tests are listed under the module and have `go_file` and `go_method` populated.
- Dependencies point to other valid modules.
### Step 6: Verify test extraction
List all extracted tests to confirm test files were parsed:
```bash
dotnet run --project tools/NatsNet.PortTracker -- test list --db porting.db
```
Spot-check a few individual tests for detail:
```bash
dotnet run --project tools/NatsNet.PortTracker -- test show 1 --db porting.db
```
Verify that each test has a module assignment and that the `feature_id` link is
populated where the analyzer could infer the connection from naming conventions
(e.g., `TestConnect` links to a feature named `Connect`).
### Step 7: Review inter-module dependencies
Check the dependency graph for a representative module:
```bash
dotnet run --project tools/NatsNet.PortTracker -- dependency show module 1 --db porting.db
```
Also view the full blocked-items report to see the overall dependency shape:
```bash
dotnet run --project tools/NatsNet.PortTracker -- dependency blocked --db porting.db
```
And check which items have no unported dependencies and are ready to start:
```bash
dotnet run --project tools/NatsNet.PortTracker -- dependency ready --db porting.db
```
### Step 8: Review extracted library mappings
List all external Go libraries that were detected:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library list --db porting.db
```
All entries should have status `not_mapped` at this point. Library mapping is
handled in Phase 3.
### Step 9: Generate a baseline summary report
Create a summary snapshot to use as a reference for Phase 2 verification:
```bash
dotnet run --project tools/NatsNet.PortTracker -- report summary --db porting.db
```
Optionally export a full markdown report for archival:
```bash
dotnet run --project tools/NatsNet.PortTracker -- report export --format md --output docs/reports/phase-1-baseline.md --db porting.db
```
## Completion Criteria
Phase 1 is complete when ALL of the following are true:
- [ ] `porting.db` exists and contains data in all five tables (modules, features,
unit_tests, dependencies, library_mappings).
- [ ] All Go source files under `golang/nats-server/server/` are accounted for
(no files silently skipped without a logged warning).
- [ ] All public and private functions/methods are extracted as features.
- [ ] All `Test*` and `Benchmark*` functions are extracted as unit_tests.
- [ ] Test-to-feature links are populated where naming conventions allow inference.
- [ ] Module-level dependencies are recorded in the dependencies table.
- [ ] External import paths are recorded in the library_mappings table.
- [ ] `phase check 1` shows all checklist items marked `[x]`:
```bash
dotnet run --project tools/NatsNet.PortTracker -- phase check 1 --db porting.db
```
Expected:
```
Phase 1: Analysis & Schema
Run Go AST analyzer, populate DB schema, map libraries
Phase 1 Checklist:
[x] Modules populated: <N>
[x] Features populated: <N>
[x] Unit tests populated: <N>
[x] Dependencies mapped: <N>
[x] Libraries identified: <N>
[ ] All libraries mapped: 0/<N>
```
Note: The "All libraries mapped" item will be unchecked -- that is expected.
Library mapping is the concern of Phase 3.
## Troubleshooting
### CGO_ENABLED not set or build fails with "gcc not found"
The `go-sqlite3` driver requires C compilation. Make sure you have a C compiler
installed and CGO is enabled:
```bash
# macOS -- Xcode command line tools
xcode-select --install
# Then build with explicit CGO
CGO_ENABLED=1 go build -o go-analyzer .
```
### "cannot find package" errors during Go build
The analyzer depends on `github.com/mattn/go-sqlite3`. Run:
```bash
cd tools/go-analyzer
go mod download
go mod verify
```
### Wrong source path
The `--source` flag must point to the root of the cloned nats-server repository
(the directory that contains the `server/` subdirectory). If you see
"discovering files: no such file or directory", verify:
```bash
ls golang/nats-server/server/
```
### Database locked errors
If you run the analyzer while another process has `porting.db` open, SQLite may
report a lock error. Close any other connections (including `sqlite3` CLI
sessions) and retry. The schema enables WAL mode to reduce lock contention:
```sql
PRAGMA journal_mode=WAL;
```
### Analyzer prints warnings but continues
Warnings like "Warning: skipping server/foo.go: <parse error>" mean an individual
file could not be parsed. The analyzer continues with remaining files. Investigate
any warnings -- they may indicate a Go version mismatch or syntax not yet
supported by the `go/ast` parser at your Go version.
### Empty database after analyzer runs
If the analyzer prints zeros for all counts, verify that:
1. The `--source` path is correct and contains Go files.
2. The `--schema` path points to a valid `porting-schema.sql`.
3. The `--db` path is writable.
You can inspect the database directly:
```bash
sqlite3 porting.db "SELECT COUNT(*) FROM modules;"
sqlite3 porting.db "SELECT COUNT(*) FROM features;"
sqlite3 porting.db "SELECT COUNT(*) FROM unit_tests;"
```

View File

@@ -0,0 +1,315 @@
# Phase 2: Verification of Captured Items
## Objective
Verify that the Phase 1 decomposition captured every Go source file, function,
test, and dependency accurately. Compare database counts against independent
baselines derived directly from the filesystem. Identify and fix any gaps before
proceeding to library mapping and porting.
## Prerequisites
- Phase 1 is complete (`porting.db` is populated).
- The Go source at `golang/nats-server/` has not changed since the Phase 1
analyzer run. If the source was updated, re-run the Phase 1 analyzer first.
- `dotnet`, `sqlite3`, `find`, `grep`, and `wc` are available on your PATH.
## Steps
### Step 1: Generate the summary report
Start with a high-level view of what the database contains:
```bash
dotnet run --project tools/NatsNet.PortTracker -- report summary --db porting.db
```
Record the counts for modules, features, unit tests, and library mappings. These
are the numbers you will verify in subsequent steps.
### Step 2: Count Go source files on disk
Count non-test `.go` files under the server directory (the scope of the analyzer):
```bash
find golang/nats-server/server -name "*.go" ! -name "*_test.go" ! -path "*/configs/*" ! -path "*/testdata/*" | wc -l
```
This should produce approximately 109 files. Compare this count against the
number of distinct `go_file` values in the features table:
```bash
sqlite3 porting.db "SELECT COUNT(DISTINCT go_file) FROM features;"
```
If the database count is lower, some source files may have been skipped. Check
the analyzer stderr output for warnings, or list the missing files:
```bash
sqlite3 porting.db "SELECT DISTINCT go_file FROM features ORDER BY go_file;" > /tmp/db_files.txt
find golang/nats-server/server -name "*.go" ! -name "*_test.go" ! -path "*/configs/*" ! -path "*/testdata/*" -exec realpath --relative-to=golang/nats-server {} \; | sort > /tmp/disk_files.txt
diff /tmp/db_files.txt /tmp/disk_files.txt
```
### Step 3: Count Go test files on disk
```bash
find golang/nats-server/server -name "*_test.go" ! -path "*/configs/*" ! -path "*/testdata/*" | wc -l
```
This should produce approximately 85 files. Compare against distinct test files
in the database:
```bash
sqlite3 porting.db "SELECT COUNT(DISTINCT go_file) FROM unit_tests;"
```
### Step 4: Compare function counts
Count all exported and unexported functions in source files on disk:
```bash
grep -r "^func " golang/nats-server/server/ --include="*.go" --exclude="*_test.go" | grep -v "/configs/" | grep -v "/testdata/" | wc -l
```
Compare against the features count from the database:
```bash
sqlite3 porting.db "SELECT COUNT(*) FROM features;"
```
The numbers should be close. Small discrepancies can occur because:
- The `grep` approach counts lines starting with `func` which may miss functions
with preceding comments on the same line or multi-line signatures.
- The AST parser used by the analyzer is more accurate; it finds all `func`
declarations regardless of formatting.
If the database count is significantly lower (more than 5% off), investigate.
### Step 5: Compare test function counts
Count test functions on disk:
```bash
grep -r "^func Test" golang/nats-server/server/ --include="*_test.go" | wc -l
```
Also count benchmarks:
```bash
grep -r "^func Benchmark" golang/nats-server/server/ --include="*_test.go" | wc -l
```
Compare the combined total against the unit_tests table:
```bash
sqlite3 porting.db "SELECT COUNT(*) FROM unit_tests;"
```
### Step 6: Run the phase check command
The PortTracker has a built-in Phase 1 checklist that verifies all tables are
populated:
```bash
dotnet run --project tools/NatsNet.PortTracker -- phase check 1 --db porting.db
```
All items except "All libraries mapped" should show `[x]`.
### Step 7: Check for orphaned items
Look for features that are not linked to any module (should be zero):
```bash
sqlite3 porting.db "SELECT COUNT(*) FROM features WHERE module_id NOT IN (SELECT id FROM modules);"
```
Look for tests that are not linked to any module (should be zero):
```bash
sqlite3 porting.db "SELECT COUNT(*) FROM unit_tests WHERE module_id NOT IN (SELECT id FROM modules);"
```
Look for test-to-feature links that point to non-existent features:
```bash
sqlite3 porting.db "SELECT COUNT(*) FROM unit_tests WHERE feature_id IS NOT NULL AND feature_id NOT IN (SELECT id FROM features);"
```
Look for dependencies that reference non-existent source or target items:
```bash
sqlite3 porting.db "
SELECT COUNT(*) FROM dependencies
WHERE (source_type = 'module' AND source_id NOT IN (SELECT id FROM modules))
OR (target_type = 'module' AND target_id NOT IN (SELECT id FROM modules))
OR (source_type = 'feature' AND source_id NOT IN (SELECT id FROM features))
OR (target_type = 'feature' AND target_id NOT IN (SELECT id FROM features))
OR (source_type = 'unit_test' AND source_id NOT IN (SELECT id FROM unit_tests))
OR (target_type = 'unit_test' AND target_id NOT IN (SELECT id FROM unit_tests));
"
```
All of these queries should return 0.
### Step 8: Review the largest modules
The largest modules are the most likely to have issues. List modules sorted by
feature count:
```bash
sqlite3 porting.db "
SELECT m.id, m.name, m.go_line_count,
COUNT(f.id) as feature_count
FROM modules m
LEFT JOIN features f ON f.module_id = m.id
GROUP BY m.id
ORDER BY feature_count DESC
LIMIT 10;
"
```
For each of the top 3 modules, do a manual spot-check:
```bash
dotnet run --project tools/NatsNet.PortTracker -- module show <id> --db porting.db
```
Scroll through the features list and verify that the functions look correct
(check a few against the actual Go source file).
### Step 9: Validate the dependency graph
Check for any circular module dependencies (modules that depend on each other):
```bash
sqlite3 porting.db "
SELECT d1.source_id, d1.target_id
FROM dependencies d1
JOIN dependencies d2
ON d1.source_type = d2.target_type AND d1.source_id = d2.target_id
AND d1.target_type = d2.source_type AND d1.target_id = d2.source_id
WHERE d1.source_type = 'module' AND d1.target_type = 'module';
"
```
Circular dependencies are not necessarily wrong (Go packages can have them via
interfaces), but they should be reviewed.
Check which items are blocked by unported dependencies:
```bash
dotnet run --project tools/NatsNet.PortTracker -- dependency blocked --db porting.db
```
And confirm that at least some items are ready to port (have no unported deps):
```bash
dotnet run --project tools/NatsNet.PortTracker -- dependency ready --db porting.db
```
### Step 10: Verify library import completeness
Ensure every external import found in the source is tracked:
```bash
sqlite3 porting.db "SELECT COUNT(*) FROM library_mappings;"
```
Cross-check against a manual count of unique non-stdlib imports:
```bash
grep -rh "\"" golang/nats-server/server/ --include="*.go" | \
grep -oP '"\K[^"]+' | \
grep '\.' | \
sort -u | \
wc -l
```
This is an approximate check. The AST-based analyzer is more accurate than grep
for import extraction, but the numbers should be in the same ballpark.
### Step 11: Export a verification snapshot
Save the current state as a markdown report for your records:
```bash
dotnet run --project tools/NatsNet.PortTracker -- report export \
--format md \
--output docs/reports/phase-2-verification.md \
--db porting.db
```
## Completion Criteria
Phase 2 is complete when ALL of the following are true:
- [ ] Source file counts on disk match distinct `go_file` counts in the database
(within a small margin for intentionally excluded directories).
- [ ] Feature counts from `grep` are within 5% of the database count (AST is the
authoritative source).
- [ ] Test function counts from `grep` match the database count closely.
- [ ] No orphaned features (all linked to valid modules).
- [ ] No orphaned tests (all linked to valid modules).
- [ ] No broken test-to-feature links.
- [ ] No dangling dependency references.
- [ ] Dependency graph is reviewed -- circular deps (if any) are acknowledged.
- [ ] `dependency ready` returns at least one item (the graph has valid roots).
- [ ] Library mappings table contains all external imports.
- [ ] `phase check 1` passes with all items except "All libraries mapped" checked.
## Troubleshooting
### File count mismatch is large
If the disk file count exceeds the database count by more than a few files,
re-run the analyzer with stderr visible:
```bash
./tools/go-analyzer/go-analyzer \
--source golang/nats-server \
--db porting.db \
--schema porting-schema.sql 2>&1 | tee /tmp/analyzer.log
```
Search for warnings:
```bash
grep "Warning" /tmp/analyzer.log
```
Common causes:
- Files with build tags that prevent parsing (e.g., `//go:build ignore`).
- Files in excluded directories (`configs/`, `testdata/`).
- Syntax errors in Go files that the parser cannot handle.
### Feature count is significantly different
The AST parser counts every `func` declaration, including unexported helper
functions. The `grep` baseline only matches lines starting with `func `. If
features that have multiline signatures like:
```go
func (s *Server) handleConnection(
conn net.Conn,
) {
```
...they will be missed by grep but found by the AST parser. Trust the database
count as authoritative.
### Orphaned records found
If orphaned records exist, the analyzer may have a bug or the database was
partially populated from a prior run. The safest fix is to:
1. Delete the database: `rm porting.db`
2. Re-run Phase 1 from Step 1.
### Tests not linked to features
The analyzer uses naming conventions to link tests to features (e.g.,
`TestConnect` maps to a feature containing `Connect`). If many tests show
`feature_id = NULL`, this is expected for tests whose names do not follow the
convention. These links can be manually added later if needed.

View File

@@ -0,0 +1,283 @@
# Phase 3: Library Mapping
## Objective
Map every external Go dependency detected by the analyzer to its .NET equivalent.
This includes Go standard library packages, well-known third-party libraries, and
NATS ecosystem packages. When Phase 3 is complete, the `library suggest` command
returns an empty list and every import has a documented .NET migration path.
## Prerequisites
- Phases 1 and 2 are complete (database is populated and verified).
- Familiarity with both the Go standard library and .NET BCL / NuGet ecosystem.
- A working `dotnet` CLI for running PortTracker commands.
## Steps
### Step 1: List all unmapped libraries
Start by seeing everything that needs attention:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library suggest --db porting.db
```
This shows all library_mappings entries with status `not_mapped`, sorted by import
path. The output includes the Go import path, the library name, and a usage
description.
If the list is empty, all libraries are already mapped and Phase 3 is complete.
### Step 2: Review the full library list
To see both mapped and unmapped libraries in one view:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library list --db porting.db
```
You can also filter by status:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library list --status not_mapped --db porting.db
dotnet run --project tools/NatsNet.PortTracker -- library list --status mapped --db porting.db
```
### Step 3: Map each library
For each unmapped library, determine the appropriate .NET equivalent using the
reference table below, then record the mapping:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library map <id> \
--package "<NuGet package or BCL>" \
--namespace "<.NET namespace>" \
--notes "<migration notes>" \
--db porting.db
```
**Example -- mapping `encoding/json`:**
```bash
dotnet run --project tools/NatsNet.PortTracker -- library map 1 \
--package "System.Text.Json" \
--namespace "System.Text.Json" \
--notes "Use JsonSerializer. Consider source generators for AOT." \
--db porting.db
```
**Example -- mapping `github.com/klauspost/compress`:**
```bash
dotnet run --project tools/NatsNet.PortTracker -- library map 12 \
--package "System.IO.Compression" \
--namespace "System.IO.Compression" \
--notes "S2/Snappy codec needs evaluation; may need custom impl or IronSnappy NuGet." \
--db porting.db
```
Repeat for every entry in the `library suggest` output.
### Step 4: Handle libraries that need custom implementations
Some Go libraries have no direct .NET equivalent and will require custom code.
For these, record the mapping with a descriptive note:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library map <id> \
--package "Custom" \
--namespace "NatsNet.Internal" \
--notes "No direct equivalent; requires custom implementation. See <details>." \
--db porting.db
```
### Step 5: Verify all libraries are mapped
Run the suggest command again -- it should return an empty list:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library suggest --db porting.db
```
Expected output:
```
All libraries have been mapped!
```
Also verify via the full list:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library list --db porting.db
```
Every entry should show status `mapped` (or `verified` if you have already
validated the mapping in code).
### Step 6: Run the phase check
Confirm Phase 1 now shows full completion including library mappings:
```bash
dotnet run --project tools/NatsNet.PortTracker -- phase check 1 --db porting.db
```
Expected:
```
Phase 1 Checklist:
[x] Modules populated: <N>
[x] Features populated: <N>
[x] Unit tests populated: <N>
[x] Dependencies mapped: <N>
[x] Libraries identified: <N>
[x] All libraries mapped: <N>/<N>
```
### Step 7: Export the mapping report
Save the complete library mapping state for reference during porting:
```bash
dotnet run --project tools/NatsNet.PortTracker -- report export \
--format md \
--output docs/reports/phase-3-library-mapping.md \
--db porting.db
```
## Common Go to .NET Mappings Reference
Use this table as a starting point when determining .NET equivalents. Adapt based
on the specific usage patterns found in the NATS server source.
### Go Standard Library
| Go Package | .NET Equivalent | Notes |
|---|---|---|
| `encoding/json` | `System.Text.Json` | Use `JsonSerializer`; consider source generators for performance |
| `encoding/binary` | `System.Buffers.Binary.BinaryPrimitives` | For endian-aware reads/writes |
| `encoding/base64` | `System.Convert` | `Convert.ToBase64String` / `Convert.FromBase64String` |
| `encoding/hex` | `System.Convert` | `Convert.ToHexString` (.NET 5+) |
| `encoding/pem` | `System.Security.Cryptography.PemEncoding` | .NET 5+ |
| `sync` | `System.Threading` | `Mutex` -> `lock` / `Monitor`; `RWMutex` -> `ReaderWriterLockSlim`; `WaitGroup` -> `CountdownEvent`; `Once` -> `Lazy<T>` |
| `sync/atomic` | `System.Threading.Interlocked` | `Interlocked.Increment`, `CompareExchange`, etc. |
| `net` | `System.Net.Sockets` | `TcpListener`, `TcpClient`, `Socket` |
| `net/http` | `System.Net.Http` / `Microsoft.AspNetCore` | Client: `HttpClient`; Server: Kestrel / minimal APIs |
| `net/url` | `System.Uri` | `Uri`, `UriBuilder` |
| `crypto/tls` | `System.Net.Security.SslStream` | Wrap `NetworkStream` with `SslStream` |
| `crypto/x509` | `System.Security.Cryptography.X509Certificates` | `X509Certificate2` |
| `crypto/sha256` | `System.Security.Cryptography.SHA256` | `SHA256.HashData()` (.NET 8+) |
| `crypto/ed25519` | `System.Security.Cryptography` | `Ed25519` support in .NET 9+ |
| `crypto/rand` | `System.Security.Cryptography.RandomNumberGenerator` | `RandomNumberGenerator.Fill()` |
| `time` | `System.TimeSpan` / `System.Threading.Timer` | `time.Duration` -> `TimeSpan`; `time.Ticker` -> `PeriodicTimer`; `time.After` -> `Task.Delay` |
| `time` (parsing) | `System.DateTime` / `System.DateTimeOffset` | `DateTime.Parse`, custom formats |
| `fmt` | String interpolation / `String.Format` | `$"..."` for most cases; `String.Format` for dynamic |
| `io` | `System.IO` | `Reader` -> `Stream`; `Writer` -> `Stream`; `io.Copy` -> `Stream.CopyTo` |
| `io/fs` | `System.IO` | `Directory`, `File`, `FileInfo` |
| `bufio` | `System.IO.BufferedStream` | Or `StreamReader` / `StreamWriter` |
| `bytes` | `System.Buffers` / `MemoryStream` | `bytes.Buffer` -> `MemoryStream` or `ArrayBufferWriter<byte>` |
| `strings` | `System.String` / `System.Text.StringBuilder` | Most methods have direct equivalents |
| `strconv` | `int.Parse`, `double.Parse`, etc. | Or `Convert` class |
| `context` | `CancellationToken` | `context.Context` -> `CancellationToken`; `context.WithCancel` -> `CancellationTokenSource` |
| `os` | `System.Environment` / `System.IO` | `os.Exit` -> `Environment.Exit`; file ops -> `File` class |
| `os/signal` | `System.Runtime.Loader.AssemblyLoadContext` | `UnloadingEvent` or `Console.CancelKeyPress` |
| `path/filepath` | `System.IO.Path` | `Path.Combine`, `Path.GetDirectoryName`, etc. |
| `sort` | `System.Linq` / `Array.Sort` | LINQ `.OrderBy()` or in-place `Array.Sort` |
| `math` | `System.Math` | Direct equivalent |
| `math/rand` | `System.Random` | `Random.Shared` for thread-safe usage (.NET 6+) |
| `regexp` | `System.Text.RegularExpressions.Regex` | Consider source generators for compiled patterns |
| `errors` | `System.Exception` | Go errors -> .NET exceptions; `errors.Is` -> pattern matching |
| `log` | `Serilog` | Project choice: Serilog via `Microsoft.Extensions.Logging` |
| `testing` | `xUnit` | `testing.T` -> xUnit `[Fact]`/`[Theory]`; `testing.B` -> BenchmarkDotNet |
| `flag` | `System.CommandLine` | Or `Microsoft.Extensions.Configuration` |
| `embed` | Embedded resources | `.csproj` `<EmbeddedResource>` items |
| `runtime` | `System.Runtime` / `System.Environment` | `runtime.GOOS` -> `RuntimeInformation.IsOSPlatform` |
### NATS Ecosystem Libraries
| Go Package | .NET Equivalent | Notes |
|---|---|---|
| `github.com/nats-io/jwt/v2` | Custom / evaluate existing | JWT claims for NATS auth; may need custom implementation matching NATS JWT spec |
| `github.com/nats-io/nkeys` | Custom implementation | Ed25519 key pairs for NATS authentication; use `System.Security.Cryptography` Ed25519 |
| `github.com/nats-io/nuid` | Custom / `System.Guid` | NATS unique IDs; simple custom implementation or adapt to `Guid` if format is flexible |
| `github.com/nats-io/nats.go` | `NATS.Net` (official) | Only used in tests; the official .NET NATS client |
### Third-Party Libraries
| Go Package | .NET Equivalent | Notes |
|---|---|---|
| `github.com/klauspost/compress` | `System.IO.Compression` | General compression: `GZipStream`, `DeflateStream`. S2/Snappy: evaluate IronSnappy NuGet or custom port |
| `github.com/minio/highwayhash` | Custom / NuGet | HighwayHash implementation; search NuGet or port the algorithm |
| `golang.org/x/crypto` | `System.Security.Cryptography` | `bcrypt` -> `Rfc2898DeriveBytes` or BCrypt.Net NuGet; `argon2` -> Konscious.Security NuGet |
| `golang.org/x/sys` | `System.Runtime.InteropServices` | Platform-specific syscalls -> P/Invoke or `RuntimeInformation` |
| `golang.org/x/time` | `System.Threading.RateLimiting` | `rate.Limiter` -> `RateLimiter` (.NET 7+); `TokenBucketRateLimiter` or `SlidingWindowRateLimiter` |
| `golang.org/x/text` | `System.Globalization` | Unicode normalization, encoding detection |
## Mapping Decision Guidelines
When choosing a .NET equivalent, follow these priorities:
1. **BCL first**: Prefer built-in .NET Base Class Library types over NuGet packages.
2. **Official packages second**: If BCL does not cover it, prefer
`Microsoft.*` or `System.*` NuGet packages.
3. **Well-maintained NuGet third**: Choose packages with active maintenance,
high download counts, and compatible licenses.
4. **Custom implementation last**: Only write custom code when no suitable
package exists. Document the rationale in the mapping notes.
For each mapping, consider:
- **API surface**: Does the .NET equivalent cover all methods used in the Go code?
- **Performance**: Are there performance-critical paths that need benchmarking?
- **Thread safety**: Go's concurrency model differs from .NET. Note any
synchronization concerns.
- **Platform support**: Does the .NET package work on all target platforms
(Linux, macOS, Windows)?
## Completion Criteria
Phase 3 is complete when ALL of the following are true:
- [ ] `library suggest` returns "All libraries have been mapped!"
- [ ] Every entry in `library list` shows status `mapped` or `verified`.
- [ ] Each mapping includes a `--package` (the NuGet package or BCL assembly),
a `--namespace` (the .NET namespace to use), and `--notes` (migration
guidance).
- [ ] `phase check 1` shows all items checked including "All libraries mapped".
- [ ] A mapping report has been exported for reference.
## Troubleshooting
### "Library <id> not found"
The ID you passed to `library map` does not exist. Run `library suggest` to get
the current list of IDs and their import paths.
### Unsure which .NET package to use
For unfamiliar Go packages:
1. Check what the package does in the Go source (look at the import usage in the
files listed by the analyzer).
2. Search NuGet.org for equivalent functionality.
3. Check if the Go package is a thin wrapper around a well-known algorithm that
.NET implements natively.
4. When in doubt, map it as "Custom" with detailed notes and revisit during
the porting phase.
### Multiple .NET options for one Go package
When there are several valid .NET equivalents (e.g., `Newtonsoft.Json` vs
`System.Text.Json`), prefer the one that:
- Is part of the BCL or a Microsoft package.
- Has better performance characteristics.
- Has source generator support for AOT compilation.
Record the alternatives in the `--notes` field so the decision can be revisited.
### Stdlib packages showing as unmapped
The analyzer classifies imports as stdlib vs external based on whether the first
path component contains a dot. Standard library packages like `encoding/json`,
`net/http`, etc. should still be recorded in the library_mappings table so that
every import path has a documented .NET migration path. Map them using the
reference table above.