# TASK 2.1: Create AnomalyDetectorAgent Interface and Result Types

## Summary

Define the interface for the anomaly detector agent and its result types. The agent is generic - it receives a MonitorSpec (with plain text instructions) and MCP tools (for database access), then uses LLM reasoning to detect anomalies.

## Dependencies

- TASK 1.1 (MonitorSpec entity)

## Design Principles

- **Generic**: The agent knows nothing about specific databases, tables, or KPIs. All domain knowledge comes from the MonitorSpec's plain text prompt.
- **MCP-driven**: Database access is through MCP tools passed to the agent. The agent (LLM) formulates its own queries.
- **No typed models**: No prep-time DTOs, no query builders, no domain-specific code. The LLM interprets raw query results.

## Files to Create

### 1. `backend/Kds.Ai.AnomalyDetector/Agents/IAnomalyDetectorAgent.cs`

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

namespace Kds.Ai.AnomalyDetector.Agents;

/// <summary>
/// Interface for the anomaly detection agent.
/// The agent receives a MonitorSpec describing what to monitor (in plain text)
/// and uses MCP tools to access data and detect anomalies.
/// </summary>
public interface IAnomalyDetectorAgent
{
    /// <summary>
    /// Run anomaly detection based on the provided monitor specification.
    /// The agent will use the MonitorSpec's SystemPrompt as instructions and
    /// formulate its own data queries via MCP tools.
    /// </summary>
    /// <param name="spec">The monitor specification with plain text instructions</param>
    /// <param name="analysisTime">The point in time to analyze (defaults to now)</param>
    /// <param name="ct">Cancellation token</param>
    /// <returns>Detection result with findings and optional alert recommendations</returns>
    Task<AnomalyDetectionResult> RunDetectionAsync(
        MonitorSpec spec,
        DateTimeOffset analysisTime,
        CancellationToken ct = default);
}
```

### 2. `backend/Kds.Ai.AnomalyDetector/Agents/AnomalyDetectionResult.cs`

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

namespace Kds.Ai.AnomalyDetector.Agents;

/// <summary>
/// Result of an anomaly detection run.
/// Contains the structured output from the agent's analysis.
/// </summary>
public sealed record AnomalyDetectionResult
{
    /// <summary>
    /// Whether any anomaly was detected
    /// </summary>
    public required bool AnomalyDetected { get; init; }

    /// <summary>
    /// Recommended severity if anomaly detected
    /// </summary>
    public EventSeverity? Severity { get; init; }

    /// <summary>
    /// Brief summary of findings (for alert summary field)
    /// </summary>
    public string? Summary { get; init; }

    /// <summary>
    /// Detailed analysis in Markdown format (for alert content field)
    /// </summary>
    public string? DetailedAnalysis { get; init; }

    /// <summary>
    /// Individual anomaly findings
    /// </summary>
    public IReadOnlyList<AnomalyFinding> Findings { get; init; } = [];

    /// <summary>
    /// Full conversation history / reasoning trace (for debugging)
    /// </summary>
    public string? Reasoning { get; init; }

    /// <summary>
    /// Token usage during the detection run
    /// </summary>
    public int? TotalTokens { get; init; }

    /// <summary>
    /// Any errors or warnings encountered during detection
    /// </summary>
    public IReadOnlyList<string> Warnings { get; init; } = [];

    /// <summary>
    /// Create a result indicating no anomaly was found
    /// </summary>
    public static AnomalyDetectionResult NoAnomaly(string? reasoning = null) => new()
    {
        AnomalyDetected = false,
        Reasoning = reasoning
    };

    /// <summary>
    /// Create a result indicating detection failed
    /// </summary>
    public static AnomalyDetectionResult Failed(string error) => new()
    {
        AnomalyDetected = false,
        Warnings = [error]
    };
}

/// <summary>
/// A specific anomaly finding reported by the agent
/// </summary>
public sealed record AnomalyFinding
{
    /// <summary>
    /// Human-readable description of the anomaly
    /// </summary>
    public required string Description { get; init; }

    /// <summary>
    /// Severity of this specific finding
    /// </summary>
    public EventSeverity Severity { get; init; }

    /// <summary>
    /// The time period affected (as described by the agent)
    /// </summary>
    public string? AffectedPeriod { get; init; }

    /// <summary>
    /// Additional context or evidence as free-form text
    /// </summary>
    public string? Evidence { get; init; }
}
```

## Design Decisions

### No Factory Pattern

There is one generic agent, not multiple typed agents. The MonitorSpec's plain text prompt determines what the agent monitors. No `MonitorType` discriminator, no factory.

### No Domain-Specific DTOs

The agent gets raw data from MCP tool calls (e.g., `mysql_query` returns result sets). The LLM interprets the data. No `PrepTimeHourlyStats`, `OrderTypeBreakdown`, etc.

### Simplified Result

- `AnomalyFinding` is intentionally simple - just description, severity, period, and evidence as text
- No `ZScore`, `DeviationPercent`, `Confidence` etc. - these are for the LLM to reason about in its analysis, not for typed fields
- The `DetailedAnalysis` Markdown field is where the agent puts its rich analysis

### emit_conclusion Tool

The `emit_conclusion` tool (defined in TASK 2.2) is the only non-MCP tool we define. It gives the agent a structured way to report findings that map to `AnomalyDetectionResult`.

## Acceptance Criteria

- [ ] `IAnomalyDetectorAgent` interface created
- [ ] `AnomalyDetectionResult` record created with all properties
- [ ] `AnomalyFinding` record created
- [ ] Static factory methods `NoAnomaly()` and `Failed()` work correctly
- [ ] No domain-specific (prep-time, KDSDev) types or references
- [ ] Solution builds without errors

## Notes

- The agent is generic - all domain knowledge comes from MonitorSpec.SystemPrompt
- Database access is via MCP tools, not code-level services
- The LLM decides what SQL to run, how to analyze results, and what constitutes an anomaly
