- 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
9.8 KiB
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.dbis 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, andwcare available on your PATH.
Source and Target Locations
| Component | Path |
|---|---|
| Go source code | golang/ (specifically golang/nats-server/) |
| .NET ported version | dotnet/ |
Steps
Step 1: Generate the summary report
Start with a high-level view of what the database contains:
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):
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:
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:
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
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:
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:
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:
sqlite3 porting.db "SELECT COUNT(*) FROM features;"
The numbers should be close. Small discrepancies can occur because:
- The
grepapproach counts lines starting withfuncwhich 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
funcdeclarations 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:
grep -r "^func Test" golang/nats-server/server/ --include="*_test.go" | wc -l
Also count benchmarks:
grep -r "^func Benchmark" golang/nats-server/server/ --include="*_test.go" | wc -l
Compare the combined total against the unit_tests table:
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:
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):
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):
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:
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:
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:
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:
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):
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:
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):
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:
sqlite3 porting.db "SELECT COUNT(*) FROM library_mappings;"
Cross-check against a manual count of unique non-stdlib imports:
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:
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_filecounts in the database (within a small margin for intentionally excluded directories). - Feature counts from
grepare within 5% of the database count (AST is the authoritative source). - Test function counts from
grepmatch 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 readyreturns at least one item (the graph has valid roots).- Library mappings table contains all external imports.
phase check 1passes 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:
./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:
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:
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:
- Delete the database:
rm porting.db - 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.