using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace StellaOps.Policy.Engine.Endpoints; public static class VerifyDeterminismEndpoints { public static RouteGroupBuilder MapVerifyDeterminismEndpoints(this IEndpointRouteBuilder endpoints) { var group = endpoints.MapGroup("/api/v1/verify") .WithTags("Verification"); group.MapPost("/determinism", HandleVerifyDeterminismAsync) .WithName("VerifyDeterminism") .WithDescription("Verify that a verdict can be deterministically replayed") .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest); return group; } private static async Task HandleVerifyDeterminismAsync( [FromBody] VerifyDeterminismRequest request, [FromServices] IReplayVerificationService verifyService, CancellationToken ct) { if (string.IsNullOrEmpty(request.SnapshotId) || string.IsNullOrEmpty(request.VerdictId)) { return Results.BadRequest(new { error = "snapshotId and verdictId are required" }); } var result = await verifyService.VerifyAsync(request.SnapshotId, request.VerdictId, ct); return Results.Ok(result); } } public record VerifyDeterminismRequest { public string SnapshotId { get; init; } = string.Empty; public string VerdictId { get; init; } = string.Empty; } public record VerificationResult { public string Status { get; init; } = "pending"; public string OriginalDigest { get; init; } = string.Empty; public string ReplayedDigest { get; init; } = string.Empty; public string MatchType { get; init; } = "unknown"; public List Differences { get; init; } = new(); public int Duration { get; init; } public DateTime VerifiedAt { get; init; } = DateTime.UtcNow; } public record Difference { public string Field { get; init; } = string.Empty; public string Original { get; init; } = string.Empty; public string Replayed { get; init; } = string.Empty; public string Severity { get; init; } = "minor"; } // Service interface (would be implemented elsewhere) public interface IReplayVerificationService { Task VerifyAsync(string snapshotId, string verdictId, CancellationToken ct = default); }