/** Domain that produced a CandidateEvent. Extend via declaration merging. */
type TriggerSourceName = "intel" | "pipeline" | "family" | "finance" | "compliance" | "health" | "calendar" | "tech" | "growth";
/**
 * When should this signal reach the operator?
 * - "now"            — surface immediately (Telegram alert, push)
 * - "morning_brief"  — include in the next morning briefing
 * - "weekly_brief"   — queue for the weekly digest
 */
type Urgency = "now" | "morning_brief" | "weekly_brief";
/** Supported delivery channels. Dashboard and email are defined for Batch 4. */
type ChannelName = "telegram" | "push" | "dashboard" | "email";
/**
 * How the operator responded to a surfaced signal. Drives the
 * CalibrationLearner's multiplier updates.
 */
type OperatorResponse = "acted" | "dismissed" | "more_like_this" | "less_like_this";
/**
 * A raw signal from a TriggerSource before scoring.
 *
 * `payload` is source-specific. Scorers inspect `payload.baseRelevance`
 * (number 0–1) if present; all other fields are optional context used by
 * channel formatters (title, summary, url, clientId, etc.).
 */
interface CandidateEvent {
    /** Stable identifier — uuid or a deterministic source-specific key. */
    id: string;
    sourceName: TriggerSourceName;
    /** Source-specific signal data. Scorers and formatters may read any field. */
    payload: Record<string, unknown>;
    occurredAt: Date;
    /** If set, do not surface this event after this timestamp. */
    expiresAt?: Date;
}
/**
 * Runtime context for one operator (a human principal or a Sentinel
 * sub-agent). Scorers and channels read this to personalise output.
 */
interface OperatorContext {
    operatorId: string;
    /**
     * Arbitrary recent-activity metadata. Channels may read
     * `recentActivity.telegramChatId` (number) to route delivery.
     */
    recentActivity?: Record<string, unknown>;
    /**
     * Priority tags. The rule-based scorer boosts candidates whose payload
     * text matches any tag.
     */
    priorities?: string[];
    /**
     * Ordered channel preference. Pipeline picks the first channel that
     * exists in the registered channel map. Fallback: "telegram".
     */
    preferredChannels?: ChannelName[];
    /**
     * Pre-loaded calibration overrides. Exposed for scorers that read their
     * own multipliers; the pipeline does not use this field directly.
     */
    calibration?: Record<string, number>;
}
/** The output of a RelevanceScorer for a single CandidateEvent. */
interface RelevanceScore {
    /** Normalised relevance: 0.0 (noise) → 1.0 (surface immediately). */
    score: number;
    urgency: Urgency;
    /** Human-readable description of which inputs produced this score. */
    rationale: string;
}
/**
 * A fully resolved, delivery-ready message produced by the pipeline for
 * each candidate that clears the score threshold.
 */
interface SurfacingMessage {
    candidate: CandidateEvent;
    score: RelevanceScore;
    channel: ChannelName;
    /** Formatted body text appropriate for the target channel. */
    body: string;
    /**
     * Optional call-to-action items. Channels render these as inline keyboard
     * buttons (Telegram), action links (email), or tap targets (push).
     *
     * `action` is the opaque callback_data string the channel encodes into
     * the button; consumers parse it in their callback handler.
     */
    cta?: {
        label: string;
        action: string;
    }[];
}

export type { CandidateEvent as C, OperatorContext as O, RelevanceScore as R, SurfacingMessage as S, TriggerSourceName as T, Urgency as U, ChannelName as a, OperatorResponse as b };
