Spensara Spensara Knowledge Base & Documentation Repository

Repository Docs & Knowledge Base

Consolidated Spensara documentation repository (722 Markdown & architecture documents in ../repository)
Built Word Documents (.docx): Spensara Overview (.docx) Capability Assessment (.docx) Brink POS Ingestion Analysis (.docx) The Borg Ingestion Architecture (.docx)

Implementation Specs (157)

Detailed engineering and feature implementation specifications.
implementation-specs/specs/AnomalyDetection/TASK1.2.md 5,667 bytes · Updated Oct 23, 2026 10:44 AM EDT
Raw File

TASK 1.2: Create MonitorRun Entity for Execution History

Summary

Create the MonitorRun entity that tracks each execution of a monitor, including status, timing, results, and any alerts generated.

Dependencies

  • TASK 1.1 (MonitorSpec entity must exist for foreign key relationship)

Files to Create

1. backend/Kds.Ai.Data/Enums/MonitorRunStatus.cs

csharp
namespace Kds.Ai.Data.Enums;

public enum MonitorRunStatus
{
    /// <summary>
    /// Run is queued but not yet started
    /// </summary>
    Pending,
    
    /// <summary>
    /// Run is currently executing
    /// </summary>
    Running,
    
    /// <summary>
    /// Run completed successfully (may or may not have found anomalies)
    /// </summary>
    Completed,
    
    /// <summary>
    /// Run failed due to an error
    /// </summary>
    Failed,
    
    /// <summary>
    /// Run was cancelled before completion
    /// </summary>
    Cancelled
}

2. backend/Kds.Ai.Data/Entities/MonitorRun.cs

csharp
using Kds.Ai.Data.Enums;

namespace Kds.Ai.Data.Entities;

public sealed class MonitorRun
{
    public Guid Id { get; set; }
    
    /// <summary>
    /// Foreign key to the monitor specification
    /// </summary>
    public Guid MonitorSpecId { get; set; }
    
    /// <summary>
    /// Navigation property to the monitor spec
    /// </summary>
    public MonitorSpec MonitorSpec { get; set; } = null!;
    
    /// <summary>
    /// Current status of the run
    /// </summary>
    public MonitorRunStatus Status { get; set; }
    
    /// <summary>
    /// When the run started
    /// </summary>
    public DateTimeOffset StartedAt { get; set; }
    
    /// <summary>
    /// When the run completed (null if still running)
    /// </summary>
    public DateTimeOffset? CompletedAt { get; set; }
    
    /// <summary>
    /// The time window being analyzed (start)
    /// </summary>
    public DateTimeOffset AnalysisWindowStart { get; set; }
    
    /// <summary>
    /// The time window being analyzed (end)
    /// </summary>
    public DateTimeOffset AnalysisWindowEnd { get; set; }
    
    /// <summary>
    /// JSON summary of findings and analysis
    /// </summary>
    public string? ResultSummary { get; set; }
    
    /// <summary>
    /// Error message if the run failed
    /// </summary>
    public string? ErrorMessage { get; set; }
    
    /// <summary>
    /// Number of anomalies detected in this run
    /// </summary>
    public int AnomaliesDetected { get; set; }
    
    /// <summary>
    /// Navigation property to the emitted alerts (one per detected anomaly)
    /// </summary>
    public ICollection<AlertEvent> AlertEvents { get; set; } = [];
    
    /// <summary>
    /// Total tokens used by LLM during this run (for cost tracking)
    /// </summary>
    public int? TokensUsed { get; set; }
    
    /// <summary>
    /// Duration of the run in milliseconds
    /// </summary>
    public long? DurationMs { get; set; }
}

3. backend/Kds.Ai.Data/Configurations/MonitorRunConfiguration.cs

csharp
using Kds.Ai.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Kds.Ai.Data.Configurations;

public sealed class MonitorRunConfiguration : IEntityTypeConfiguration<MonitorRun>
{
    public void Configure(EntityTypeBuilder<MonitorRun> builder)
    {
        builder.ToTable("MonitorRuns");
        
        builder.HasKey(x => x.Id);
        
        builder.Property(x => x.Status)
            .IsRequired()
            .HasMaxLength(50);
        
        builder.Property(x => x.StartedAt)
            .IsRequired();
        
        builder.Property(x => x.ResultSummary)
            .HasColumnType("longtext");
        
        builder.Property(x => x.ErrorMessage)
            .HasMaxLength(2000);
        
        // Relationships
        builder.HasOne(x => x.MonitorSpec)
            .WithMany(x => x.Runs)
            .HasForeignKey(x => x.MonitorSpecId)
            .OnDelete(DeleteBehavior.Cascade);
        
        builder.HasMany(x => x.AlertEvents)
            .WithMany()
            .UsingEntity("MonitorRunAlertEvents");
        
        // Indexes
        builder.HasIndex(x => x.MonitorSpecId);
        builder.HasIndex(x => x.Status);
        builder.HasIndex(x => x.StartedAt);
        builder.HasIndex(x => new { x.MonitorSpecId, x.StartedAt });
    }
}

Files to Modify

4. backend/Kds.Ai.Data/KdsAiDbContext.cs

Add DbSet property:

csharp
public DbSet<MonitorRun> MonitorRuns => Set<MonitorRun>();

Note: Configuration is automatically applied via ApplyConfigurationsFromAssembly - no manual registration needed.

Acceptance Criteria

  • [ ] MonitorRunStatus enum created with all specified values
  • [ ] MonitorRun entity created with all specified properties
  • [ ] Fluent API configuration follows project conventions (sealed class, no data annotations)
  • [ ] Foreign key relationship to MonitorSpec with cascade delete
  • [ ] Many-to-many relationship to AlertEvents via join table MonitorRunAlertEvents
  • [ ] No explicit enum conversion (handled globally by ConfigureConventions)
  • [ ] DbSet registered in KdsAiDbContext
  • [ ] Solution builds without errors

Notes

  • A single MonitorRun can detect multiple anomalies and emit multiple AlertEvents
  • The many-to-many relationship uses a join table MonitorRunAlertEvents
  • TokensUsed and DurationMs are for observability/cost tracking
  • AnalysisWindowStart/End track what time period was analyzed (independent of when the run happened)
  • Configurations are auto-discovered via ApplyConfigurationsFromAssembly