# AGENTS.md ## Project Summary This project ports the NATS messaging server from Go to .NET 10 C#. The Go source (~130K LOC) is the reference at `golang/nats-server/`. Porting progress is tracked in an SQLite database (`porting.db`) managed by the PortTracker CLI tool. ## Folder Layout ``` natsnet/ ├── golang/nats-server/ # Go source (read-only reference) ├── dotnet/ │ ├── src/ZB.MOM.NatsNet.Server/ # Main server library │ ├── src/ZB.MOM.NatsNet.Server.Host/ # Host entry point │ └── tests/ │ ├── ZB.MOM.NatsNet.Server.Tests/ # Unit tests │ └── ZB.MOM.NatsNet.Server.IntegrationTests/ # Integration tests ├── tools/NatsNet.PortTracker/ # CLI tracking tool ├── docs/standards/dotnet-standards.md # .NET coding standards (MUST follow) ├── docs/plans/phases/ # Phase instruction guides ├── reports/current.md # Latest porting status ├── porting.db # SQLite tracking database └── porting-schema.sql # Database schema ``` ## Build and Test ```bash # Build the solution dotnet build dotnet/ # Run all unit tests dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ # Run filtered tests (by namespace/class) dotnet test --filter "FullyQualifiedName~ZB.MOM.NatsNet.Server.Tests.Protocol" \ dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ # Run integration tests dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.IntegrationTests/ # Generate porting report ./reports/generate-report.sh ``` ## .NET Coding Standards **MUST follow all rules in `docs/standards/dotnet-standards.md`.** Critical rules (non-negotiable): - .NET 10, C# latest, nullable enabled - **xUnit 3** + **Shouldly** + **NSubstitute** for testing - **NEVER use FluentAssertions or Moq** — these are forbidden - PascalCase for public members, `_camelCase` for private fields - File-scoped namespaces: `ZB.MOM.NatsNet.Server.[Module]` - Use `CancellationToken` on all async signatures - Use `ReadOnlySpan` on hot paths - Test naming: `[Method]_[Scenario]_[Expected]` - Test class naming: `[ClassName]Tests` - Structured logging with `ILogger` and `LogContext.PushProperty` ## PortTracker CLI All tracking commands use this base: ```bash dotnet run --project tools/NatsNet.PortTracker -- --db porting.db ``` ### Querying | Command | Purpose | |---------|---------| | `report summary` | Show overall porting progress | | `dependency ready` | List items ready to port (no unported deps) | | `dependency blocked` | List items blocked by unported deps | | `feature list --status ` | List features by status | | `feature list --module ` | List features in a module | | `feature show ` | Show feature details (Go source path, .NET target) | | `test list --status ` | List tests by status | | `test show ` | Show test details | | `module list` | List all modules | | `module show ` | Show module with its features and tests | ### Updating Status | Command | Purpose | |---------|---------| | `feature update --status ` | Update one feature | | `feature batch-update --ids "1-10" --set-status --execute` | Bulk update features | | `test update --status ` | Update one test | | `test batch-update --ids "1-10" --set-status --execute` | Bulk update tests | | `module update --status ` | Update module status | ### Audit Verification Status updates are verified against Roslyn audit results. If the audit disagrees with your requested status, add `--override "reason"` to force it. ```bash feature update 42 --status verified --override "manually verified logic" ``` ### Audit Commands | Command | Purpose | |---------|---------| | `audit --type features` | Dry-run audit of features against .NET source | | `audit --type tests` | Dry-run audit of tests against test project | | `audit --type features --execute` | Apply audit classifications to DB | | `audit --type tests --execute` | Apply test audit classifications to DB | ### Valid Statuses ``` not_started → stub → complete → verified └→ n_a (not applicable) └→ deferred (blocked, needs server infra) ``` ### Batch ID Syntax `--ids` accepts: ranges `"100-200"`, lists `"1,5,10"`, or mixed `"1-5,10,20-25"`. All batch commands default to dry-run. Add `--execute` to apply. ## Porting Workflow ### Finding Work 1. Query for features ready to port: ```bash dotnet run --project tools/NatsNet.PortTracker -- dependency ready --db porting.db ``` 2. Or find deferred/stub features in a specific module: ```bash dotnet run --project tools/NatsNet.PortTracker -- feature list --module --status deferred --db porting.db ``` 3. To find tests that need implementing: ```bash dotnet run --project tools/NatsNet.PortTracker -- test list --status stub --db porting.db dotnet run --project tools/NatsNet.PortTracker -- test list --status deferred --db porting.db ``` ### Implementing a Feature 1. **Claim it** — mark as stub before starting: ```bash dotnet run --project tools/NatsNet.PortTracker -- feature update --status stub --db porting.db ``` 2. **Read the Go source** — use `feature show ` to get the Go file path and line numbers, then read the Go implementation. 3. **Write idiomatic C#** — translate intent, not lines: - Use `async`/`await`, not goroutine translations - Use `Channel` for Go channels - Use `CancellationToken` for `context.Context` - Use `ReadOnlySpan` on hot paths - Use `Lock` (C# 13) for `sync.Mutex` - Use `ReaderWriterLockSlim` for `sync.RWMutex` 4. **Ensure it compiles** — run `dotnet build dotnet/` 5. **Mark complete**: ```bash dotnet run --project tools/NatsNet.PortTracker -- feature update --status complete --db porting.db ``` ### Implementing a Unit Test 1. **Read the Go test** — use `test show ` to get Go source location. 2. **Read the corresponding .NET feature** to understand the API surface. 3. **Write the test** in `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/` using xUnit 3 + Shouldly + NSubstitute. 4. **Run it**: ```bash dotnet test --filter "FullyQualifiedName~TestClassName" \ dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ ``` 5. **Mark verified** (if passing): ```bash dotnet run --project tools/NatsNet.PortTracker -- test update --status verified --db porting.db ``` ### After Completing Work 1. Run affected tests to verify nothing broke. 2. Update DB status for all items you changed. 3. Check what's newly unblocked: ```bash dotnet run --project tools/NatsNet.PortTracker -- dependency ready --db porting.db ``` 4. Generate updated report: ```bash ./reports/generate-report.sh ``` ## Go to .NET Translation Reference | Go Pattern | .NET Equivalent | |------------|-----------------| | `goroutine` | `Task.Run` or `async`/`await` | | `chan T` | `Channel` | | `select` | `Task.WhenAny` | | `sync.Mutex` | `Lock` (C# 13) | | `sync.RWMutex` | `ReaderWriterLockSlim` | | `sync.WaitGroup` | `Task.WhenAll` or `CountdownEvent` | | `atomic.Int64` | `Interlocked` methods on `long` field | | `context.Context` | `CancellationToken` | | `defer` | `try`/`finally` or `using` | | `error` return | Exceptions or Result pattern | | `[]byte` | `byte[]`, `ReadOnlySpan`, `ReadOnlyMemory` | | `map[K]V` | `Dictionary` or `ConcurrentDictionary` | | `interface{}` | `object` or generics | | `time.Duration` | `TimeSpan` | | `weak.Pointer[T]` | `WeakReference` |