import type { ChartCapability, ChartDataProfile, ChartRubric, ChartVariant } from "./chartCapabilityTypes";
import type { IntentId } from "./intents";
import { type AudienceProfile } from "./audienceProfile";
/**
 * Where a proposal came from. Used by scoring + ranking to weight
 * trusted sources (manual hand-curated variants) above heuristic
 * suggestions and model-generated proposals that need verification.
 */
export type VariantProposalSource = "manual" | "heuristic" | "model";
/**
 * A "what if we tried this configuration?" candidate. Closely
 * related to `ChartVariant`, but with explicit provenance and an
 * optional `buildProps` so model-generated proposals can carry
 * their own prop-construction logic without registering a full
 * capability.
 *
 * The `id` is the durable identifier — the scoring side keys
 * results by it so consumers can correlate proposals across
 * propose/evaluate rounds.
 */
export interface VariantProposal {
    /** Stable identifier — `<component>:<key>` is the conventional shape. */
    id: string;
    /** Component this proposal would render. */
    baseComponent: string;
    /** Human-facing label, usually a registered variant label or generated heuristic label. */
    label?: string;
    /**
     * Per-intent score deltas applied on top of the base capability's
     * `intentScores`. Use sparingly — over-large deltas are a sign the
     * proposal should be a separate chart, not a variant.
     */
    intentDeltas?: Partial<Record<IntentId, number>>;
    /** Rubric deltas applied on top of the base capability's rubric. */
    rubricDeltas?: Partial<ChartRubric>;
    /**
     * Build the props this proposal would pass to the component. When
     * omitted, the engine falls back to the capability's own
     * `buildProps(profile, variant)`. Model-generated proposals
     * typically provide their own.
     */
    buildProps?: (profile: ChartDataProfile, audience?: AudienceProfile) => Record<string, unknown>;
    /** Free-form natural-language rationale for the proposal. */
    rationale?: string;
    /** Where the proposal originated. */
    source: VariantProposalSource;
    /** Optional reference to a registered variant key when the proposal mirrors one. */
    variantKey?: string;
    /** Optional tags consumers can filter on (mirrors `ChartVariant.tags`). */
    tags?: ReadonlyArray<string>;
}
/**
 * Why we'd reject a proposal: missing required field, conflicts with
 * data type, audience mismatch above threshold, etc. Surfaced through
 * `VariantScore.reasons`.
 */
export type VariantRejectionReason = string;
/**
 * Result of evaluating a single proposal against a data profile and
 * (optionally) an audience. Composes with the existing
 * `suggestCharts` scoring vocabulary.
 */
export interface VariantScore {
    /** Echoes `VariantProposal.id`. */
    proposalId: string;
    /**
     * How well this proposal matches the profile + audience, 0..5.
     * Drawn from the same 0..5 scale `suggestCharts` uses so consumers
     * can mix variant proposals into a unified ranked list.
     */
    fit: number;
    /**
     * How surprising the proposal is relative to the obvious
     * recommendation, 0..1. Higher = more novel. The talk-track use
     * is "a discovery model proposed a Ridgeline where the audience
     * expected a BoxPlot."
     */
    novelty: number;
    /**
     * Risk of misleading the audience, 0..1. Higher = more risky.
     * Drives the visual treatment (warning chip, expanded caveats).
     */
    risk: number;
    /**
     * Narrative reasons assembled from the capability `fits()` gate,
     * rubric deltas, audience bias, and the discovery source. Suitable
     * for tooltips and LLM context.
     */
    reasons: ReadonlyArray<string>;
}
export interface EvaluateVariantProposalOptions {
    /** Ranking intent(s). When omitted, fit uses the mean non-zero intent score. */
    intent?: IntentId | ReadonlyArray<IntentId>;
    /** Component the user started from — used to estimate cross-family novelty. */
    baselineComponent?: string;
}
/**
 * Context handed to a discovery function. Carries everything a
 * proposer needs to inspect the existing recommendation surface:
 * the dataset profile, the audience, the already-considered
 * variants, and the intent driving the recommendation.
 */
export interface VariantDiscoveryContext {
    profile: ChartDataProfile;
    audience?: AudienceProfile;
    intent?: IntentId | ReadonlyArray<IntentId>;
    /**
     * Variants already attached to the base capability — proposers
     * should avoid re-emitting these unless they have meaningful
     * deltas a registered variant doesn't.
     */
    existingVariants?: ReadonlyArray<ChartVariant>;
}
/**
 * Signature for a proposal generator. Implementations may be
 * heuristic, LLM-driven, or hand-coded. The engine collects
 * proposals from every registered discovery function and ranks
 * the union through `evaluateVariantProposal`.
 */
export type ProposeVariantFn = (component: string, capability: ChartCapability, context: VariantDiscoveryContext) => ReadonlyArray<VariantProposal>;
/**
 * Signature for a scoring function. The default scorer composes the
 * capability's `fits()` gate, rubric deltas, and audience bias. External
 * scorers may add their own novelty/risk computations.
 */
export type EvaluateVariantProposalFn = (proposal: VariantProposal, profile: ChartDataProfile, audience?: AudienceProfile, options?: EvaluateVariantProposalOptions) => VariantScore;
/**
 * Aggregates proposals from every registered discovery function.
 *
 * Each registered function is invoked with the same `(component,
 * capability, context)` tuple; their results are concatenated and
 * deduplicated by `VariantProposal.id` (first proposer wins). A
 * proposer that throws is isolated — the error surfaces through
 * `console.warn` and the remaining proposers still run.
 *
 * The built-in proposer first emits registered `capability.variants` as
 * manual proposals, then adds conservative heuristic transforms and
 * same-intent cross-family alternatives. Registered discovery functions
 * run after that and are deduplicated by `VariantProposal.id`.
 */
export declare const proposeVariant: ProposeVariantFn;
/**
 * Evaluate a proposal against the same ingredients the capability
 * recommender uses: fits gate, intent scores, rubric deltas, and audience
 * profile. `novelty` and `risk` are discovery-specific side channels.
 */
export declare const evaluateVariantProposal: EvaluateVariantProposalFn;
/**
 * Register a discovery function. Returns an unregister callback.
 *
 * `proposeVariant` invokes every registered function and deduplicates
 * by `VariantProposal.id`. External ML-driven proposers plug in here
 * without API change.
 *
 * Built-in heuristic discovery lives in `proposeVariant` directly. This
 * registry is the extension surface for consumers and model integrations.
 */
export declare function registerVariantDiscovery(fn: ProposeVariantFn): () => void;
/**
 * Snapshot the registered discovery functions. Primarily for testing
 * and for the engine implementation to iterate registered proposers.
 */
export declare function getRegisteredVariantDiscovery(): ReadonlyArray<ProposeVariantFn>;
/**
 * Drop every registered discovery function. Exposed for tests and
 * for consumers who need to swap discovery models between sessions.
 */
export declare function clearVariantDiscovery(): void;
