204 lines
7.1 KiB
C#
204 lines
7.1 KiB
C#
namespace NATS.Server.Tests.Parity;
|
|
|
|
public sealed record DriftRow(string Feature, string DifferencesStatus, string EvidenceStatus, string Reason);
|
|
|
|
public sealed class JetStreamParityTruthMatrixReport
|
|
{
|
|
public JetStreamParityTruthMatrixReport(IReadOnlyList<DriftRow> driftRows, IReadOnlyList<string> contradictions)
|
|
{
|
|
DriftRows = driftRows;
|
|
Contradictions = contradictions;
|
|
}
|
|
|
|
public IReadOnlyList<DriftRow> DriftRows { get; }
|
|
public IReadOnlyList<string> Contradictions { get; }
|
|
}
|
|
|
|
public static class JetStreamParityTruthMatrix
|
|
{
|
|
public static JetStreamParityTruthMatrixReport Load(string differencesRelativePath, string mapRelativePath)
|
|
{
|
|
var repositoryRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", ".."));
|
|
var differencesPath = Path.Combine(repositoryRoot, differencesRelativePath);
|
|
var mapPath = Path.Combine(repositoryRoot, mapRelativePath);
|
|
File.Exists(differencesPath).ShouldBeTrue();
|
|
File.Exists(mapPath).ShouldBeTrue();
|
|
|
|
var differences = ParityRowInspector.Load(differencesRelativePath).Rows;
|
|
var matrixRows = ParseTruthMatrix(mapPath);
|
|
var drift = new List<DriftRow>();
|
|
|
|
if (matrixRows.Count == 0)
|
|
{
|
|
drift.Add(new DriftRow(
|
|
"JetStream Truth Matrix",
|
|
"missing",
|
|
"missing",
|
|
"docs/plans/2026-02-23-jetstream-remaining-parity-map.md must include a populated 'JetStream Truth Matrix' table."));
|
|
}
|
|
|
|
foreach (var row in matrixRows)
|
|
{
|
|
var differencesRow = differences.FirstOrDefault(r =>
|
|
string.Equals(r.Feature, row.DifferencesFeature, StringComparison.OrdinalIgnoreCase));
|
|
|
|
if (differencesRow is null)
|
|
{
|
|
drift.Add(new DriftRow(
|
|
row.Feature,
|
|
"missing",
|
|
row.EvidenceStatus,
|
|
$"Differences row '{row.DifferencesFeature}' was not found in differences.md."));
|
|
continue;
|
|
}
|
|
|
|
if (!string.Equals(differencesRow.DotNetStatus, "Y", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
drift.Add(new DriftRow(
|
|
row.Feature,
|
|
differencesRow.DotNetStatus,
|
|
row.EvidenceStatus,
|
|
"Differences status must be Y for a verified truth-matrix row."));
|
|
}
|
|
|
|
if (!string.Equals(row.EvidenceStatus, "verified", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
drift.Add(new DriftRow(
|
|
row.Feature,
|
|
differencesRow.DotNetStatus,
|
|
row.EvidenceStatus,
|
|
"Evidence status must be 'verified'."));
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(row.TestEvidence) || row.TestEvidence == "-")
|
|
{
|
|
drift.Add(new DriftRow(
|
|
row.Feature,
|
|
differencesRow.DotNetStatus,
|
|
row.EvidenceStatus,
|
|
"Test evidence must be provided for every truth-matrix row."));
|
|
}
|
|
}
|
|
|
|
var contradictions = ParseRemainingExplicitDeltaContradictions(differencesPath, matrixRows);
|
|
return new JetStreamParityTruthMatrixReport(drift, contradictions);
|
|
}
|
|
|
|
private static List<TruthMatrixRow> ParseTruthMatrix(string mapPath)
|
|
{
|
|
var rows = new List<TruthMatrixRow>();
|
|
var inTruthMatrix = false;
|
|
foreach (var rawLine in File.ReadLines(mapPath))
|
|
{
|
|
var line = rawLine.Trim();
|
|
if (line.StartsWith("## ", StringComparison.Ordinal))
|
|
{
|
|
inTruthMatrix = string.Equals(
|
|
line,
|
|
"## JetStream Truth Matrix",
|
|
StringComparison.OrdinalIgnoreCase);
|
|
continue;
|
|
}
|
|
|
|
if (!inTruthMatrix || !line.StartsWith("|", StringComparison.Ordinal) || line.Contains("---", StringComparison.Ordinal))
|
|
continue;
|
|
|
|
var cells = line.Trim('|').Split('|').Select(c => c.Trim()).ToArray();
|
|
if (cells.Length < 4 || string.Equals(cells[0], "Feature", StringComparison.OrdinalIgnoreCase))
|
|
continue;
|
|
|
|
rows.Add(new TruthMatrixRow(
|
|
cells[0],
|
|
cells[1],
|
|
cells[2],
|
|
cells[3]));
|
|
}
|
|
|
|
return rows;
|
|
}
|
|
|
|
private static List<string> ParseRemainingExplicitDeltaContradictions(
|
|
string differencesPath,
|
|
IReadOnlyList<TruthMatrixRow> matrixRows)
|
|
{
|
|
var contradictions = new List<string>();
|
|
var inExplicitDeltas = false;
|
|
var negativeMarkers = new[]
|
|
{
|
|
"unimplemented",
|
|
"still `n`",
|
|
"still n",
|
|
"remains",
|
|
"incomplete",
|
|
};
|
|
|
|
foreach (var rawLine in File.ReadLines(differencesPath))
|
|
{
|
|
var line = rawLine.Trim();
|
|
if (line.StartsWith("### ", StringComparison.Ordinal))
|
|
{
|
|
inExplicitDeltas = string.Equals(
|
|
line,
|
|
"### Remaining Explicit Deltas",
|
|
StringComparison.OrdinalIgnoreCase);
|
|
continue;
|
|
}
|
|
|
|
if (inExplicitDeltas && line.StartsWith("## ", StringComparison.Ordinal))
|
|
{
|
|
inExplicitDeltas = false;
|
|
continue;
|
|
}
|
|
|
|
if (!inExplicitDeltas || !line.StartsWith("- ", StringComparison.Ordinal))
|
|
continue;
|
|
|
|
var normalizedLine = line.ToLowerInvariant();
|
|
if (!negativeMarkers.Any(marker => normalizedLine.Contains(marker, StringComparison.Ordinal)))
|
|
continue;
|
|
|
|
foreach (var row in matrixRows.Where(r =>
|
|
string.Equals(r.EvidenceStatus, "verified", StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
if (MentionsFeature(normalizedLine, row))
|
|
{
|
|
contradictions.Add($"{row.Feature}: {line[2..].Trim()}");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return contradictions;
|
|
}
|
|
|
|
private static bool MentionsFeature(string normalizedLine, TruthMatrixRow row)
|
|
{
|
|
var tokens = Tokenize(row.Feature)
|
|
.Concat(Tokenize(row.DifferencesFeature))
|
|
.Where(t => t.Length >= 4)
|
|
.Distinct(StringComparer.Ordinal)
|
|
.ToArray();
|
|
|
|
if (tokens.Length == 0)
|
|
return false;
|
|
|
|
var matches = tokens.Count(t => normalizedLine.Contains(t, StringComparison.Ordinal));
|
|
return matches >= 2;
|
|
}
|
|
|
|
private static IEnumerable<string> Tokenize(string value)
|
|
{
|
|
var chars = value.ToLowerInvariant()
|
|
.Select(c => char.IsLetterOrDigit(c) ? c : ' ')
|
|
.ToArray();
|
|
return new string(chars)
|
|
.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
|
}
|
|
|
|
private sealed record TruthMatrixRow(
|
|
string Feature,
|
|
string DifferencesFeature,
|
|
string EvidenceStatus,
|
|
string TestEvidence);
|
|
}
|