Implements batch list/show/ready/next/start/complete commands with dependency validation, migrates 42 implementation batches (2377 features, 2087 tests) from porting_batches.db into the live tracking database, and documents the batch workflow in AGENTS.md.
8.9 KiB
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
# 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,
_camelCasefor private fields - File-scoped namespaces:
ZB.MOM.NatsNet.Server.[Module] - Use
CancellationTokenon all async signatures - Use
ReadOnlySpan<byte>on hot paths - Test naming:
[Method]_[Scenario]_[Expected] - Test class naming:
[ClassName]Tests - Structured logging with
ILogger<T>andLogContext.PushProperty
PortTracker CLI
All tracking commands use this base:
dotnet run --project tools/NatsNet.PortTracker -- <command> --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 <s> |
List features by status |
feature list --module <id> |
List features in a module |
feature show <id> |
Show feature details (Go source path, .NET target) |
test list --status <s> |
List tests by status |
test show <id> |
Show test details |
module list |
List all modules |
module show <id> |
Show module with its features and tests |
Updating Status
| Command | Purpose |
|---|---|
feature update <id> --status <s> |
Update one feature |
feature batch-update --ids "1-10" --set-status <s> --execute |
Bulk update features |
test update <id> --status <s> |
Update one test |
test batch-update --ids "1-10" --set-status <s> --execute |
Bulk update tests |
module update <id> --status <s> |
Update module status |
batch start <id> |
Mark batch as in-progress (validates deps) |
batch complete <id> |
Mark batch as complete (validates all items done) |
Batch Querying
| Command | Purpose |
|---|---|
batch list |
List all implementation batches |
batch list --status <s> |
Filter batches by status |
batch show <id> |
Show batch details with features and tests |
batch ready |
List batches ready to start (deps met) |
batch next |
Show next recommended batch |
Audit Verification
Status updates are verified against Roslyn audit results. If the audit disagrees with your requested status, add --override "reason" to force it.
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
- Query for features ready to port:
dotnet run --project tools/NatsNet.PortTracker -- dependency ready --db porting.db
- Or find deferred/stub features in a specific module:
dotnet run --project tools/NatsNet.PortTracker -- feature list --module <id> --status deferred --db porting.db
- To find tests that need implementing:
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
Batch Workflow
Work is organized into 42 implementation batches with dependency ordering. Use batches to find and track work:
- Find the next batch —
batch nextreturns the lowest-priority ready batch:
dotnet run --project tools/NatsNet.PortTracker -- batch next --db porting.db
- Start it — marks the batch as in-progress (validates dependencies are met):
dotnet run --project tools/NatsNet.PortTracker -- batch start <id> --db porting.db
- See all items — lists every feature and test in the batch:
dotnet run --project tools/NatsNet.PortTracker -- batch show <id> --db porting.db
-
Implement features first, then write/port the tests.
-
Complete it — validates all features and tests are verified/complete/n_a:
dotnet run --project tools/NatsNet.PortTracker -- batch complete <id> --db porting.db
The system enforces dependency ordering — you cannot start a batch until all batches it depends on are complete. Use batch ready to see all currently available batches.
Implementing a Feature
- Claim it — mark as stub before starting:
dotnet run --project tools/NatsNet.PortTracker -- feature update <id> --status stub --db porting.db
-
Read the Go source — use
feature show <id>to get the Go file path and line numbers, then read the Go implementation. -
Write idiomatic C# — translate intent, not lines:
- Use
async/await, not goroutine translations - Use
Channel<T>for Go channels - Use
CancellationTokenforcontext.Context - Use
ReadOnlySpan<byte>on hot paths - Use
Lock(C# 13) forsync.Mutex - Use
ReaderWriterLockSlimforsync.RWMutex
- Use
-
Ensure it compiles — run
dotnet build dotnet/ -
Mark complete:
dotnet run --project tools/NatsNet.PortTracker -- feature update <id> --status complete --db porting.db
Implementing a Unit Test
- Read the Go test — use
test show <id>to get Go source location. - Read the corresponding .NET feature to understand the API surface.
- Write the test in
dotnet/tests/ZB.MOM.NatsNet.Server.Tests/using xUnit 3 + Shouldly + NSubstitute. - Run it:
dotnet test --filter "FullyQualifiedName~TestClassName" \
dotnet/tests/ZB.MOM.NatsNet.Server.Tests/
- Mark verified (if passing):
dotnet run --project tools/NatsNet.PortTracker -- test update <id> --status verified --db porting.db
After Completing Work
- Run affected tests to verify nothing broke.
- Update DB status for all items you changed.
- Check what's newly unblocked:
dotnet run --project tools/NatsNet.PortTracker -- dependency ready --db porting.db
- Generate updated report:
./reports/generate-report.sh
Go to .NET Translation Reference
| Go Pattern | .NET Equivalent |
|---|---|
goroutine |
Task.Run or async/await |
chan T |
Channel<T> |
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<byte>, ReadOnlyMemory<byte> |
map[K]V |
Dictionary<K,V> or ConcurrentDictionary<K,V> |
interface{} |
object or generics |
time.Duration |
TimeSpan |
weak.Pointer[T] |
WeakReference<T> |