sprints work

This commit is contained in:
StellaOps Bot
2025-12-24 21:46:08 +02:00
parent 43e2af88f6
commit b9f71fc7e9
161 changed files with 29566 additions and 527 deletions

View File

@@ -0,0 +1,111 @@
/**
* Edge Delta Detection
* Sprint: SPRINT_9100_0001_0003 (Content-Addressed EdgeId)
* Tasks: EDGEID-9100-012 through EDGEID-9100-014
*
* Provides delta detection between evidence graphs at the edge level.
*/
using System.Collections.Immutable;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
namespace StellaOps.Resolver;
/// <summary>
/// Delta between two graphs at the edge level.
/// </summary>
/// <param name="AddedEdges">Edges present in new graph but not in old.</param>
/// <param name="RemovedEdges">Edges present in old graph but not in new.</param>
/// <param name="ModifiedEdges">Edges with same (src, kind, dst) but different attributes.</param>
public sealed record EdgeDelta(
ImmutableArray<Edge> AddedEdges,
ImmutableArray<Edge> RemovedEdges,
ImmutableArray<(Edge Old, Edge New)> ModifiedEdges)
{
/// <summary>
/// Returns true if there are no differences.
/// </summary>
public bool IsEmpty => AddedEdges.IsEmpty && RemovedEdges.IsEmpty && ModifiedEdges.IsEmpty;
}
/// <summary>
/// Interface for detecting edge deltas.
/// </summary>
public interface IEdgeDeltaDetector
{
/// <summary>
/// Detects differences between two graphs at the edge level.
/// </summary>
EdgeDelta Detect(EvidenceGraph old, EvidenceGraph @new);
}
/// <summary>
/// Default edge delta detector.
/// </summary>
public sealed class DefaultEdgeDeltaDetector : IEdgeDeltaDetector
{
public EdgeDelta Detect(EvidenceGraph old, EvidenceGraph @new)
{
ArgumentNullException.ThrowIfNull(old);
ArgumentNullException.ThrowIfNull(@new);
// Group edges by their identity (EdgeId), which is based on (src, kind, dst)
var oldEdges = old.Edges.ToDictionary(e => e.Id);
var newEdges = @new.Edges.ToDictionary(e => e.Id);
var added = new List<Edge>();
var removed = new List<Edge>();
var modified = new List<(Edge Old, Edge New)>();
// Find added and modified
foreach (var (edgeId, newEdge) in newEdges)
{
if (oldEdges.TryGetValue(edgeId, out var oldEdge))
{
// Same EdgeId - check if attributes changed
if (!AttributesEqual(oldEdge.Attrs, newEdge.Attrs))
{
modified.Add((oldEdge, newEdge));
}
}
else
{
added.Add(newEdge);
}
}
// Find removed
foreach (var (edgeId, oldEdge) in oldEdges)
{
if (!newEdges.ContainsKey(edgeId))
{
removed.Add(oldEdge);
}
}
return new EdgeDelta(
added.ToImmutableArray(),
removed.ToImmutableArray(),
modified.ToImmutableArray());
}
private static bool AttributesEqual(JsonElement? a, JsonElement? b)
{
if (a is null && b is null) return true;
if (a is null || b is null) return false;
var aHash = ComputeAttrsHash(a.Value);
var bHash = ComputeAttrsHash(b.Value);
return aHash == bHash;
}
private static string ComputeAttrsHash(JsonElement attrs)
{
var json = attrs.GetRawText();
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(json));
return Convert.ToHexString(hash).ToLowerInvariant();
}
}