# TASK 4.1: Create IMonitorRunOrchestrator Interface

## Summary

Define the interface for the orchestrator that coordinates the complete anomaly detection execution flow: loading specs, running the agent, and emitting results.

## Dependencies

- TASK 1.2 (MonitorRun entity)
- TASK 2.1 (AnomalyDetectionResult)

## Files to Create

### 1. `backend/Kds.Ai.AnomalyDetector/Orchestration/IMonitorRunOrchestrator.cs`

```csharp
using Kds.Ai.Data.Entities;

namespace Kds.Ai.AnomalyDetector.Orchestration;

/// <summary>
/// Orchestrates the execution of monitor runs, coordinating between
/// MonitorSpec loading, agent execution, and result emission
/// </summary>
public interface IMonitorRunOrchestrator
{
    /// <summary>
    /// Execute a monitor run by MonitorSpec ID
    /// </summary>
    /// <param name="monitorSpecId">The ID of the MonitorSpec to run</param>
    /// <param name="analysisTime">Point in time to analyze (default: now)</param>
    /// <param name="options">Execution options</param>
    /// <param name="ct">Cancellation token</param>
    /// <returns>The completed MonitorRun record</returns>
    Task<MonitorRun> ExecuteAsync(
        Guid monitorSpecId,
        DateTimeOffset? analysisTime = null,
        RunOptions? options = null,
        CancellationToken ct = default);
    
    /// <summary>
    /// Execute a monitor run with a provided MonitorSpec
    /// (useful for testing or one-off runs without database storage)
    /// </summary>
    /// <param name="spec">The MonitorSpec to execute</param>
    /// <param name="analysisTime">Point in time to analyze (default: now)</param>
    /// <param name="options">Execution options</param>
    /// <param name="ct">Cancellation token</param>
    /// <returns>The completed MonitorRun record</returns>
    Task<MonitorRun> ExecuteAsync(
        MonitorSpec spec,
        DateTimeOffset? analysisTime = null,
        RunOptions? options = null,
        CancellationToken ct = default);
    
    /// <summary>
    /// Execute all active monitors (State == Active)
    /// </summary>
    /// <param name="analysisTime">Point in time to analyze</param>
    /// <param name="options">Execution options</param>
    /// <param name="ct">Cancellation token</param>
    /// <returns>List of completed MonitorRun records</returns>
    Task<IReadOnlyList<MonitorRun>> ExecuteAllActiveAsync(
        DateTimeOffset? analysisTime = null,
        RunOptions? options = null,
        CancellationToken ct = default);
}

/// <summary>
/// Options for controlling monitor execution
/// </summary>
public record RunOptions
{
    /// <summary>
    /// If true, run the analysis but don't emit alerts or save to database
    /// </summary>
    public bool DryRun { get; init; } = false;
    
    /// <summary>
    /// If true, suppress alert emission even if anomaly detected
    /// </summary>
    public bool SuppressAlerts { get; init; } = false;
    
    /// <summary>
    /// Override the analysis window start time
    /// </summary>
    public DateTimeOffset? WindowStart { get; init; }
    
    /// <summary>
    /// Override the analysis window end time
    /// </summary>
    public DateTimeOffset? WindowEnd { get; init; }
    
    /// <summary>
    /// Maximum execution time before timeout
    /// </summary>
    public TimeSpan? Timeout { get; init; }
    
    /// <summary>
    /// Callback for progress reporting
    /// </summary>
    public IProgress<RunProgress>? Progress { get; init; }
    
    /// <summary>
    /// Default options
    /// </summary>
    public static RunOptions Default => new();
    
    /// <summary>
    /// Options for dry-run testing
    /// </summary>
    public static RunOptions TestRun => new()
    {
        DryRun = true,
        SuppressAlerts = true
    };
}

/// <summary>
/// Progress information during monitor execution
/// </summary>
public record RunProgress
{
    /// <summary>
    /// Current phase of execution
    /// </summary>
    public required RunPhase Phase { get; init; }
    
    /// <summary>
    /// Human-readable message
    /// </summary>
    public required string Message { get; init; }
    
    /// <summary>
    /// Progress percentage (0-100) if applicable
    /// </summary>
    public int? ProgressPercent { get; init; }
}

/// <summary>
/// Phases of monitor execution
/// </summary>
public enum RunPhase
{
    Initializing,
    LoadingSpec,
    RunningAgent,
    AnalyzingResults,
    EmittingAlerts,
    SavingResults,
    Completed,
    Failed
}
```

## Interface Design Rationale

### Multiple Entry Points

1. **By ID**: Standard case - load spec from DB and run
2. **By Spec**: Testing/ad-hoc without DB
3. **All Active**: Scheduled batch runs (monitors with `State == Active`)

### RunOptions

Flexible options enable:
- **DryRun**: Test without side effects
- **SuppressAlerts**: Run analysis without notification
- **Window Override**: Custom time ranges for historical analysis
- **Timeout**: Prevent runaway executions
- **Progress**: UI/logging integration

### Removed from Old Design

- `ExecuteAllByTypeAsync(monitorType)` - removed because MonitorSpec no longer has `MonitorType`
- `ExecuteForStoreAsync(storeGuid)` - removed because MonitorSpec no longer has `StoreGuid`
- `SkipPreflight` option - removed because preflight checks were domain-specific (data freshness); the agent can decide in its own reasoning whether data is fresh enough

### Progress Reporting

The `IProgress<RunProgress>` pattern allows:
- CLI progress indicators
- UI status updates
- Logging integration
- Debugging long-running operations

## Acceptance Criteria

- [ ] `IMonitorRunOrchestrator` interface created
- [ ] All execution methods defined
- [ ] `RunOptions` record with all options
- [ ] `RunProgress` and `RunPhase` for progress tracking
- [ ] No references to `MonitorType`, `StoreGuid`, or `IsEnabled`
- [ ] Uses `ExecuteAllActiveAsync` (not by type/store)
- [ ] Static factory methods for common option sets
- [ ] XML documentation complete
- [ ] Solution builds without errors

## Notes

- Implementation in TASK 4.2
- Consider adding `CancelAsync(Guid runId)` for aborting runs
- May want `GetRunStatusAsync(Guid runId)` for polling
- The return type is `MonitorRun` entity - consider a DTO if needed
