feat: add FeatureClassifier — heuristic-based feature classification
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# NATS .NET Porting Status Report
|
# NATS .NET Porting Status Report
|
||||||
|
|
||||||
Generated: 2026-02-27 10:16:59 UTC
|
Generated: 2026-02-27 10:17:36 UTC
|
||||||
|
|
||||||
## Modules (12 total)
|
## Modules (12 total)
|
||||||
|
|
||||||
|
|||||||
35
reports/report_2dd2321.md
Normal file
35
reports/report_2dd2321.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# NATS .NET Porting Status Report
|
||||||
|
|
||||||
|
Generated: 2026-02-27 10:17:36 UTC
|
||||||
|
|
||||||
|
## Modules (12 total)
|
||||||
|
|
||||||
|
| Status | Count |
|
||||||
|
|--------|-------|
|
||||||
|
| verified | 12 |
|
||||||
|
|
||||||
|
## Features (3673 total)
|
||||||
|
|
||||||
|
| Status | Count |
|
||||||
|
|--------|-------|
|
||||||
|
| unknown | 3394 |
|
||||||
|
| verified | 279 |
|
||||||
|
|
||||||
|
## Unit Tests (3257 total)
|
||||||
|
|
||||||
|
| Status | Count |
|
||||||
|
|--------|-------|
|
||||||
|
| deferred | 2680 |
|
||||||
|
| n_a | 187 |
|
||||||
|
| verified | 390 |
|
||||||
|
|
||||||
|
## Library Mappings (36 total)
|
||||||
|
|
||||||
|
| Status | Count |
|
||||||
|
|--------|-------|
|
||||||
|
| mapped | 36 |
|
||||||
|
|
||||||
|
|
||||||
|
## Overall Progress
|
||||||
|
|
||||||
|
**868/6942 items complete (12.5%)**
|
||||||
91
tools/NatsNet.PortTracker/Audit/FeatureClassifier.cs
Normal file
91
tools/NatsNet.PortTracker/Audit/FeatureClassifier.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
namespace NatsNet.PortTracker.Audit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Classifies features by inspecting the SourceIndexer for their .NET implementation status.
|
||||||
|
/// Priority: n_a lookup -> method-not-found -> stub detection -> verified.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class FeatureClassifier
|
||||||
|
{
|
||||||
|
public record ClassificationResult(string Status, string Reason);
|
||||||
|
|
||||||
|
public record FeatureRecord(
|
||||||
|
long Id,
|
||||||
|
string DotnetClass,
|
||||||
|
string DotnetMethod,
|
||||||
|
string GoFile,
|
||||||
|
string GoMethod);
|
||||||
|
|
||||||
|
private readonly SourceIndexer _indexer;
|
||||||
|
|
||||||
|
// N/A lookup: (goMethod pattern) -> reason
|
||||||
|
// Checked case-insensitively against go_method
|
||||||
|
private static readonly Dictionary<string, string> NaByGoMethod = new(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
["Noticef"] = ".NET uses Microsoft.Extensions.Logging",
|
||||||
|
["Debugf"] = ".NET uses Microsoft.Extensions.Logging",
|
||||||
|
["Tracef"] = ".NET uses Microsoft.Extensions.Logging",
|
||||||
|
["Warnf"] = ".NET uses Microsoft.Extensions.Logging",
|
||||||
|
["Errorf"] = ".NET uses Microsoft.Extensions.Logging",
|
||||||
|
["Fatalf"] = ".NET uses Microsoft.Extensions.Logging",
|
||||||
|
};
|
||||||
|
|
||||||
|
// N/A lookup: go_file + go_method patterns
|
||||||
|
private static readonly List<(Func<FeatureRecord, bool> Match, string Reason)> NaPatterns =
|
||||||
|
[
|
||||||
|
// Signal handling — .NET uses IHostApplicationLifetime
|
||||||
|
(f => f.GoMethod.Equals("handleSignals", StringComparison.OrdinalIgnoreCase), ".NET uses IHostApplicationLifetime"),
|
||||||
|
(f => f.GoMethod.Equals("processSignal", StringComparison.OrdinalIgnoreCase), ".NET uses IHostApplicationLifetime"),
|
||||||
|
];
|
||||||
|
|
||||||
|
public FeatureClassifier(SourceIndexer indexer)
|
||||||
|
{
|
||||||
|
_indexer = indexer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Classify a single feature. Returns status and reason.
|
||||||
|
/// </summary>
|
||||||
|
public ClassificationResult Classify(FeatureRecord feature)
|
||||||
|
{
|
||||||
|
// 1. N/A lookup — check go_method against known patterns
|
||||||
|
if (NaByGoMethod.TryGetValue(feature.GoMethod, out var naReason))
|
||||||
|
return new ClassificationResult("n_a", naReason);
|
||||||
|
|
||||||
|
foreach (var (match, reason) in NaPatterns)
|
||||||
|
{
|
||||||
|
if (match(feature))
|
||||||
|
return new ClassificationResult("n_a", reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Handle comma-separated dotnet_class (e.g. "ClosedRingBuffer,ClosedClient")
|
||||||
|
var classNames = feature.DotnetClass.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||||
|
var methodName = feature.DotnetMethod;
|
||||||
|
|
||||||
|
// Try each class name
|
||||||
|
foreach (var className in classNames)
|
||||||
|
{
|
||||||
|
var methods = _indexer.Lookup(className, methodName);
|
||||||
|
if (methods.Count > 0)
|
||||||
|
{
|
||||||
|
// Found the method — classify based on body analysis
|
||||||
|
// Use the "best" match: prefer non-stub over stub
|
||||||
|
var best = methods.OrderByDescending(m => m.StatementCount).First();
|
||||||
|
|
||||||
|
if (best.IsStub)
|
||||||
|
return new ClassificationResult("stub", $"Body is throw NotImplementedException at {Path.GetFileName(best.FilePath)}:{best.LineNumber}");
|
||||||
|
|
||||||
|
if (best.IsPartial)
|
||||||
|
return new ClassificationResult("stub", $"Partial implementation with NotImplementedException at {Path.GetFileName(best.FilePath)}:{best.LineNumber}");
|
||||||
|
|
||||||
|
return new ClassificationResult("verified", $"Method found with {best.StatementCount} statement(s) at {Path.GetFileName(best.FilePath)}:{best.LineNumber}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Method not found — check if any class exists
|
||||||
|
var anyClassFound = classNames.Any(c => _indexer.HasClass(c));
|
||||||
|
if (anyClassFound)
|
||||||
|
return new ClassificationResult("deferred", "Class exists but method not found");
|
||||||
|
|
||||||
|
return new ClassificationResult("deferred", "Class not found in .NET source");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user