Files
natsdotnet/tests/NATS.Server.Tests/Parity/JetStreamParityTruthMatrix.cs
2026-02-23 13:43:14 -05:00

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);
}