diff --git a/docs/plans/phases/phase-1-decomposition.md b/docs/plans/phases/phase-1-decomposition.md new file mode 100644 index 0000000..8c9e10c --- /dev/null +++ b/docs/plans/phases/phase-1-decomposition.md @@ -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: + Features: + Unit Tests: + Dependencies: + Imports: +``` + +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: + [x] Features populated: + [x] Unit tests populated: + [x] Dependencies mapped: + [x] Libraries identified: + [ ] All libraries mapped: 0/ +``` + +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: " 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;" +``` diff --git a/docs/plans/phases/phase-2-verification.md b/docs/plans/phases/phase-2-verification.md new file mode 100644 index 0000000..422be2a --- /dev/null +++ b/docs/plans/phases/phase-2-verification.md @@ -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 --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. diff --git a/docs/plans/phases/phase-3-library-mapping.md b/docs/plans/phases/phase-3-library-mapping.md new file mode 100644 index 0000000..8b155d8 --- /dev/null +++ b/docs/plans/phases/phase-3-library-mapping.md @@ -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 \ + --package "" \ + --namespace "<.NET namespace>" \ + --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 \ + --package "Custom" \ + --namespace "NatsNet.Internal" \ + --notes "No direct equivalent; requires custom implementation. See
." \ + --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: + [x] Features populated: + [x] Unit tests populated: + [x] Dependencies mapped: + [x] Libraries identified: + [x] All libraries mapped: / +``` + +### 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` | +| `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` | +| `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` `` 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 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.