save progress
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.VexLens.Api;
|
||||
using StellaOps.VexLens.Delta;
|
||||
using StellaOps.VexLens.NoiseGate;
|
||||
using StellaOps.VexLens.Storage;
|
||||
|
||||
namespace StellaOps.VexLens.WebService.Extensions;
|
||||
|
||||
@@ -73,6 +76,32 @@ public static class VexLensEndpointExtensions
|
||||
.WithDescription("Get projections with conflicts")
|
||||
.Produces<QueryProjectionsResponse>(StatusCodes.Status200OK);
|
||||
|
||||
// Delta/Noise-Gating endpoints
|
||||
var deltaGroup = app.MapGroup("/api/v1/vexlens/deltas")
|
||||
.WithTags("VexLens Delta")
|
||||
.WithOpenApi();
|
||||
|
||||
deltaGroup.MapPost("/compute", ComputeDeltaAsync)
|
||||
.WithName("ComputeDelta")
|
||||
.WithDescription("Compute delta report between two snapshots")
|
||||
.Produces<DeltaReportResponse>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status400BadRequest);
|
||||
|
||||
var gatingGroup = app.MapGroup("/api/v1/vexlens/gating")
|
||||
.WithTags("VexLens Gating")
|
||||
.WithOpenApi();
|
||||
|
||||
gatingGroup.MapGet("/statistics", GetGatingStatisticsAsync)
|
||||
.WithName("GetGatingStatistics")
|
||||
.WithDescription("Get aggregated noise-gating statistics")
|
||||
.Produces<AggregatedGatingStatisticsResponse>(StatusCodes.Status200OK);
|
||||
|
||||
gatingGroup.MapPost("/snapshots/{snapshotId}/gate", GateSnapshotAsync)
|
||||
.WithName("GateSnapshot")
|
||||
.WithDescription("Apply noise-gating to a snapshot")
|
||||
.Produces<GatedSnapshotResponse>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
// Issuer endpoints
|
||||
var issuerGroup = app.MapGroup("/api/v1/vexlens/issuers")
|
||||
.WithTags("VexLens Issuers")
|
||||
@@ -265,6 +294,91 @@ public static class VexLensEndpointExtensions
|
||||
return Results.Ok(conflictsOnly);
|
||||
}
|
||||
|
||||
// Delta/Noise-Gating handlers
|
||||
private static async Task<IResult> ComputeDeltaAsync(
|
||||
[FromBody] ComputeDeltaRequest request,
|
||||
[FromServices] INoiseGate noiseGate,
|
||||
[FromServices] ISnapshotStore snapshotStore,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = GetTenantId(context) ?? request.TenantId;
|
||||
|
||||
// Get snapshots
|
||||
var fromSnapshot = await snapshotStore.GetAsync(request.FromSnapshotId, tenantId, cancellationToken);
|
||||
var toSnapshot = await snapshotStore.GetAsync(request.ToSnapshotId, tenantId, cancellationToken);
|
||||
|
||||
if (fromSnapshot is null || toSnapshot is null)
|
||||
{
|
||||
return Results.BadRequest("One or both snapshot IDs not found");
|
||||
}
|
||||
|
||||
// Compute delta
|
||||
var options = NoiseGatingApiMapper.MapOptions(request.Options);
|
||||
var delta = await noiseGate.DiffAsync(fromSnapshot, toSnapshot, options, cancellationToken);
|
||||
|
||||
return Results.Ok(NoiseGatingApiMapper.MapToResponse(delta));
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetGatingStatisticsAsync(
|
||||
[FromQuery] string? tenantId,
|
||||
[FromQuery] DateTimeOffset? fromDate,
|
||||
[FromQuery] DateTimeOffset? toDate,
|
||||
[FromServices] IGatingStatisticsStore statsStore,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenant = GetTenantId(context) ?? tenantId;
|
||||
var stats = await statsStore.GetAggregatedAsync(tenant, fromDate, toDate, cancellationToken);
|
||||
|
||||
return Results.Ok(new AggregatedGatingStatisticsResponse(
|
||||
TotalSnapshots: stats.TotalSnapshots,
|
||||
TotalEdgesProcessed: stats.TotalEdgesProcessed,
|
||||
TotalEdgesAfterDedup: stats.TotalEdgesAfterDedup,
|
||||
AverageEdgeReductionPercent: stats.AverageEdgeReductionPercent,
|
||||
TotalVerdicts: stats.TotalVerdicts,
|
||||
TotalSurfaced: stats.TotalSurfaced,
|
||||
TotalDamped: stats.TotalDamped,
|
||||
AverageDampingPercent: stats.AverageDampingPercent,
|
||||
ComputedAt: DateTimeOffset.UtcNow));
|
||||
}
|
||||
|
||||
private static async Task<IResult> GateSnapshotAsync(
|
||||
string snapshotId,
|
||||
[FromBody] GateSnapshotRequest request,
|
||||
[FromServices] INoiseGate noiseGate,
|
||||
[FromServices] ISnapshotStore snapshotStore,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = GetTenantId(context) ?? request.TenantId;
|
||||
|
||||
// Get the raw snapshot
|
||||
var snapshot = await snapshotStore.GetRawAsync(snapshotId, tenantId, cancellationToken);
|
||||
if (snapshot is null)
|
||||
{
|
||||
return Results.NotFound();
|
||||
}
|
||||
|
||||
// Apply noise-gating
|
||||
var gateRequest = new NoiseGateRequest
|
||||
{
|
||||
Graph = snapshot.Graph,
|
||||
SnapshotId = snapshotId,
|
||||
Verdicts = snapshot.Verdicts
|
||||
};
|
||||
|
||||
var gatedSnapshot = await noiseGate.GateAsync(gateRequest, cancellationToken);
|
||||
|
||||
return Results.Ok(new GatedSnapshotResponse(
|
||||
SnapshotId: gatedSnapshot.SnapshotId,
|
||||
Digest: gatedSnapshot.Digest,
|
||||
CreatedAt: gatedSnapshot.CreatedAt,
|
||||
EdgeCount: gatedSnapshot.Edges.Count,
|
||||
VerdictCount: gatedSnapshot.Verdicts.Count,
|
||||
Statistics: NoiseGatingApiMapper.MapStatistics(gatedSnapshot.Statistics)));
|
||||
}
|
||||
|
||||
// Issuer handlers
|
||||
private static async Task<IResult> ListIssuersAsync(
|
||||
[FromQuery] string? category,
|
||||
|
||||
Reference in New Issue
Block a user