import { ab as LearnableWeight, M as UserOutcomeRecord, ac as OrchestrationContext, W as WeightedCard, U as UserDBInterface, C as CourseDBInterface, R as ReplanHints, a1 as StrategyContribution } from '../contentSource-BDRX_YYJ.js';
export { K as ActivityRecord, A as AdminDBInterface, v as AssignedCard, g as AssignedContent, u as AssignedCourse, t as AssignedTag, a8 as CardGenerator, aa as CardGeneratorFactory, c as ClassroomDBInterface, F as ClassroomRegistration, E as ClassroomRegistrationDesignation, H as ClassroomRegistrationDoc, e as ContentNavigationStrategyData, f as ContentNavigator, q as ContentSourceID, d as CourseInfo, L as CourseRegistration, s as CourseRegistrationDoc, b as CoursesDBInterface, a9 as GeneratorContext, G as GeneratorResult, P as HYDRATION_MARKER_ID, Q as HydrationMarker, V as NavigatorConstructor, a4 as NavigatorRole, a5 as NavigatorRoles, a3 as Navigators, j as ScheduledCard, I as SessionTrackingData, i as StudentClassroomDBInterface, h as StudyContentSource, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, S as StudySessionItem, n as StudySessionNewItem, o as StudySessionReviewItem, T as TeacherClassroomDBInterface, J as UserConfig, z as UserCourseSetting, y as UserCourseSettings, x as UserDBAuthenticator, a as UserDBReader, w as UserDBWriter, N as UserHydrationState, O as UserHydrationStatus, B as UsrCrsDataInterface, ad as computeDeviation, af as computeEffectiveWeight, ae as computeSpread, ag as createOrchestrationContext, a2 as getCardOrigin, Y as getRegisteredNavigator, $ as getRegisteredNavigatorNames, _ as getRegisteredNavigatorRole, r as getStudySource, Z as hasRegisteredNavigator, a0 as initializeNavigatorRegistry, a7 as isFilter, a6 as isGenerator, p as isReview, X as registerNavigator } from '../contentSource-BDRX_YYJ.js';
export { D as DataLayerProvider } from '../dataLayerProvider-Dpshuql4.js';
import { D as DocType, d as QuestionRecord, b as DocTypePrefixes, C as CardHistory, c as CardRecord } from '../types-legacy-4tlwHnXo.js';
export { e as CardData, f as CourseListData, h as DataShapeData, g as DisplayableData, F as Field, G as GuestUsername, Q as QualifiedCardID, i as QuestionData, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from '../types-legacy-4tlwHnXo.js';
import { DataShape, ParsedCard } from '@vue-skuilder/common';
import 'moment';

declare abstract class Loggable {
    protected abstract readonly _className: string;
    protected log(...args: unknown[]): void;
    protected error(...args: unknown[]): void;
}

/** Per-course snapshot of SRS backlog state, captured on each SRS generator run. */
interface SrsBacklogDebug {
    courseId: string;
    /** Total reviews scheduled for this course (due + not-yet-due). */
    scheduledTotal: number;
    /** Reviews eligible (due) right now. */
    dueNow: number;
    /** Healthy backlog threshold; multiplier is ×1.0 at or below this. */
    healthyBacklog: number;
    /** Global multiplier applied to every due review's urgency this run (>= 1.0, unbounded). */
    backlogMultiplier: number;
    /** Exponential growth-rate base the multiplier climbs by per multiple of healthyBacklog excess. */
    backlogGrowthRate: number;
    /** Highest review score produced this run (post-multiplier; can exceed 1.0); null if none due. */
    topReviewScore: number | null;
    /** Human-readable time until the next review comes due, or null if some are due now. */
    nextDueIn: string | null;
    /** Epoch ms of capture. */
    timestamp: number;
}
/** Current backlog snapshot for every course seen, newest-first. */
declare function getSrsBacklogDebug(): SrsBacklogDebug[];
/** Drop all captured snapshots (called on session start, alongside pipeline history). */
declare function clearSrsBacklogDebug(): void;

/**
 * A single named pressure reading. The common shape across strategies: a
 * multiplier that climbs under some accumulated condition (staleness, debt,
 * blockage), optionally clamped at a cap.
 */
interface PressureGaugeDebug {
    /** Stable identifier within the source (e.g. 'group:intro-core:target'). */
    id: string;
    /** Short display label (e.g. 'intro-core targets'). */
    label: string;
    /** Current pressure multiplier (×1.0 = no pressure). */
    multiplier: number;
    /** Clamp ceiling, if the multiplier is capped. Omit for unbounded. */
    max?: number;
    /** One-line context for the reading (counts, mode, staleness). */
    detail?: string;
    /** Expandable rows (blocked target ids, per-tag debt ages, ...). */
    items?: Array<{
        label: string;
        value?: string;
    }>;
}
/** One strategy's pressure snapshot for one course, captured once per run. */
interface StrategyPressureDebug {
    /** Producer identity — implementingClass name (e.g. 'prescribed'). */
    source: string;
    courseId: string;
    gauges: PressureGaugeDebug[];
    /**
     * Highest score this strategy emitted into the candidate pool this run;
     * null if it emitted nothing. Compare against the supplyQ head score to
     * read how the pressure is competing for slots (same crossover read as the
     * SRS panel's `top review`).
     */
    topScore?: number | null;
    /** Label of any one-shot hints emitted alongside the cards this run. */
    hintsLabel?: string;
    /** Epoch ms of capture. */
    timestamp: number;
}
/** Called by a strategy once per run. Latest snapshot per (source, course) wins. */
declare function captureStrategyPressure(snapshot: StrategyPressureDebug): void;
/** Current pressure snapshot for every source seen, newest-first. */
declare function getStrategyPressureDebug(): StrategyPressureDebug[];
/** Drop all captured snapshots (called on session start, alongside pipeline history). */
declare function clearStrategyPressureDebug(): void;

/**
 * Snapshot of the learning state for a strategy.
 *
 * Stored in the CourseDB for observability and debugging.
 * Updated periodically by the gradient learning system.
 */
interface StrategyLearningState {
    /**
     * Unique ID: "STRATEGY_LEARNING_STATE::{courseId}::{strategyId}"
     */
    _id: string;
    /** Allow CouchDB to manage revisions */
    _rev?: string;
    docType: DocType.STRATEGY_LEARNING_STATE;
    courseId: string;
    strategyId: string;
    /** Current learned weight (mirrors the strategy doc, for convenience) */
    currentWeight: LearnableWeight;
    /** Most recent regression statistics */
    regression: {
        /** Slope of the linear regression (deviation vs outcome) */
        gradient: number;
        /** Y-intercept of the regression line */
        intercept: number;
        /** R-squared value (0-1), measure of fit quality */
        rSquared: number;
        /** Number of observations used in this regression */
        sampleSize: number;
        /** ISO timestamp of when this regression was computed */
        computedAt: string;
    };
    /** Historical weight snapshots for visualization */
    history: Array<{
        timestamp: string;
        weight: number;
        confidence: number;
        gradient: number;
    }>;
    /** ISO timestamp of last update */
    updatedAt: string;
}
/**
 * Data point for gradient computation: (deviation, outcome) pair.
 */
interface GradientObservation {
    /** User's deviation for this strategy [-1, 1] */
    deviation: number;
    /** User's outcome value [0, 1] */
    outcomeValue: number;
    /** Optional: weight for this observation (default 1.0) */
    weight?: number;
}
/**
 * Result of linear regression on (deviation, outcome) pairs.
 */
interface GradientResult {
    /** Slope: positive = higher deviation correlates with better outcomes */
    gradient: number;
    /** Y-intercept */
    intercept: number;
    /** R-squared: 0-1, how well the line fits */
    rSquared: number;
    /** Number of observations */
    sampleSize: number;
}

/**
 * Extract (deviation, outcome) observations for a specific strategy
 * from a collection of UserOutcomeRecords.
 *
 * @param outcomes - Collection of outcome records (from multiple users)
 * @param strategyId - The strategy to extract observations for
 * @returns Array of gradient observations
 */
declare function aggregateOutcomesForGradient(outcomes: UserOutcomeRecord[], strategyId: string): GradientObservation[];
/**
 * Compute linear regression on (deviation, outcome) pairs.
 *
 * Uses ordinary least squares to find the best fit line:
 *   outcome = gradient * deviation + intercept
 *
 * The gradient tells us:
 * - Positive: users with higher deviation (higher weight) had better outcomes
 *             → we should increase the peak weight
 * - Negative: users with higher deviation (higher weight) had worse outcomes
 *             → we should decrease the peak weight
 * - Near zero: weight doesn't affect outcomes much
 *             → we're near optimal, increase confidence
 *
 * @param observations - Array of (deviation, outcome) pairs
 * @returns Regression result, or null if insufficient data
 */
declare function computeStrategyGradient(observations: GradientObservation[]): GradientResult | null;

/**
 * Compute updated weight based on gradient result.
 *
 * The update logic:
 * - Positive gradient: users with higher weight did better → increase weight
 * - Negative gradient: users with higher weight did worse → decrease weight
 * - Flat gradient: weight doesn't affect outcome → increase confidence
 *
 * @param current - Current learnable weight
 * @param gradient - Computed gradient result
 * @returns Updated learnable weight
 */
declare function updateStrategyWeight(current: LearnableWeight, gradient: GradientResult): LearnableWeight;
/**
 * Create or update a StrategyLearningState document.
 *
 * @param courseId - Course ID
 * @param strategyId - Strategy ID
 * @param currentWeight - Current learned weight
 * @param gradient - Gradient result from recent computation
 * @param existing - Existing learning state (if any)
 * @returns Updated learning state document
 */
declare function updateLearningState(courseId: string, strategyId: string, currentWeight: LearnableWeight, gradient: GradientResult, existing?: StrategyLearningState): StrategyLearningState;
/**
 * Input data for running a period update on a single strategy.
 */
interface PeriodUpdateInput {
    courseId: string;
    strategyId: string;
    currentWeight: LearnableWeight;
    gradient: GradientResult;
    existingState?: StrategyLearningState;
}
/**
 * Result of a period update for a single strategy.
 */
interface PeriodUpdateResult {
    strategyId: string;
    previousWeight: LearnableWeight;
    newWeight: LearnableWeight;
    gradient: GradientResult;
    learningState: StrategyLearningState;
    updated: boolean;
}
/**
 * Run a period update for a single strategy.
 *
 * This function:
 * 1. Takes the computed gradient
 * 2. Computes the new weight
 * 3. Generates the updated learning state
 *
 * Note: Actual persistence (updating strategy doc, saving learning state)
 * must be done by the caller with appropriate DB access.
 *
 * @param input - Update input data
 * @returns Update result with new weight and learning state
 */
declare function runPeriodUpdate(input: PeriodUpdateInput): PeriodUpdateResult;
/**
 * Create a default LearnableWeight for strategies that don't have one.
 */
declare function getDefaultLearnableWeight(): LearnableWeight;

interface SignalConfig {
    /** Target accuracy for "in the zone" learning (default: 0.85) */
    targetAccuracy?: number;
    /** Width of the peak plateau (default: 0.05) */
    tolerance?: number;
}
/**
 * Computes a scalar signal (0-1) representing the quality of the learning outcome.
 *
 * Current implementation focuses on "accuracy within Zone of Proximal Development".
 * Future versions should include ELO gain rate.
 *
 * @param records - List of question attempts in the period
 * @param config - Configuration for the signal function
 * @returns Score 0.0-1.0, or null if insufficient data
 */
declare function computeOutcomeSignal(records: QuestionRecord[], config?: SignalConfig): number | null;
/**
 * Scores an accuracy value based on how close it is to the target "sweet spot".
 *
 * The function defines a plateau of width (2 * tolerance) around the target
 * where score is 1.0. Outside this plateau, it falls off linearly.
 *
 * @param accuracy - Observed accuracy (0-1)
 * @param target - Target accuracy (e.g. 0.85)
 * @param tolerance - +/- range allowed for max score
 */
declare function scoreAccuracyInZone(accuracy: number, target: number, tolerance: number): number;

/**
 * Records a learning outcome for a specific period of time.
 *
 * This function:
 * 1. Computes a scalar "success" signal from the provided question records
 * 2. Re-computes the deviations that were active for this user/course
 * 3. Persists a UserOutcomeRecord to the user's database
 *
 * This record is later used by the optimization job to correlate
 * deviations with outcomes (Evolutionary Orchestration).
 *
 * @param context - Orchestration context (user, course, etc.)
 * @param periodStart - ISO timestamp of period start
 * @param periodEnd - ISO timestamp of period end (now)
 * @param records - Question records generated during this period
 * @param activeStrategyIds - IDs of strategies active in this course
 * @param eloStart - User's ELO at start of period (optional)
 * @param eloEnd - User's ELO at end of period (optional)
 * @param config - Optional configuration for signal computation
 */
declare function recordUserOutcome(context: OrchestrationContext, periodStart: string, periodEnd: string, records: QuestionRecord[], activeStrategyIds: string[], eloStart?: number, eloEnd?: number, config?: SignalConfig): Promise<void>;

/**
 * Shared context available to all filters in a pipeline.
 *
 * Built once per getWeightedCards() call and passed to each filter.
 * This avoids repeated lookups for common data like user ELO.
 */
interface FilterContext {
    /** User database interface */
    user: UserDBInterface;
    /** Course database interface */
    course: CourseDBInterface;
    /** User's global ELO score for this course */
    userElo: number;
    /** Orchestration context for evolutionary weighting */
    orchestration?: OrchestrationContext;
}
/**
 * A filter that transforms a list of weighted cards.
 *
 * Filters are pure transforms - they receive cards and context,
 * and return a modified list of cards. No delegate wrapping,
 * no side effects beyond provenance tracking.
 *
 * ## Implementation Guidelines
 *
 * 1. **Append provenance**: Every filter should add a StrategyContribution
 *    entry documenting its decision for each card.
 *
 * 2. **Use multipliers**: Adjust scores by multiplying, not replacing.
 *    This ensures filter order doesn't matter.
 *
 * 3. **Score 0 for exclusion**: To exclude a card, set score to 0.
 *    Don't filter it out - let provenance show why it was excluded.
 *
 * 4. **Don't sort**: The Pipeline handles final sorting.
 *    Filters just transform scores.
 *
 * ## Example Implementation
 *
 * ```typescript
 * const myFilter: CardFilter = {
 *   name: 'My Filter',
 *   async transform(cards, context) {
 *     return cards.map(card => {
 *       const multiplier = computeMultiplier(card, context);
 *       const newScore = card.score * multiplier;
 *       return {
 *         ...card,
 *         score: newScore,
 *         provenance: [...card.provenance, {
 *           strategy: 'myFilter',
 *           strategyName: 'My Filter',
 *           strategyId: 'MY_FILTER',
 *           action: multiplier < 1 ? 'penalized' : 'passed',
 *           score: newScore,
 *           reason: 'Explanation of decision'
 *         }]
 *       };
 *     });
 *   }
 * };
 * ```
 */
interface CardFilter {
    /** Human-readable name for this filter */
    name: string;
    /**
     * Transform a list of weighted cards.
     *
     * @param cards - Cards to transform (already scored by generator)
     * @param context - Shared context (user, course, userElo, etc.)
     * @returns Transformed cards with updated scores and provenance
     */
    transform(cards: WeightedCard[], context: FilterContext): Promise<WeightedCard[]>;
}
/**
 * Factory function type for creating filters from configuration.
 *
 * Used by PipelineAssembler to instantiate filters from strategy documents.
 */
type CardFilterFactory<TConfig = unknown> = (config: TConfig) => CardFilter;

interface DiversityRerankOptions {
    /**
     * How hard repetition is penalised. Larger → steeper demotion of repeated
     * distinctive tags. Penalty = 1 / (1 + strength·load).
     */
    strength?: number;
    /**
     * Minimum penalty multiplier. A card is never demoted below `floor × score`,
     * however much it repeats. Keeps a strong-but-repeated card from being driven
     * under downstream "well-indicated" thresholds (which would mislabel it as
     * filler and could trigger spurious quality-replans). Tunes "perturb ordering"
     * vs "annihilate candidates."
     */
    floor?: number;
}
/** Default repetition strength. See DiversityRerankOptions.strength. */
declare const DIVERSITY_STRENGTH = 0.6;
/** Default penalty floor. See DiversityRerankOptions.floor. */
declare const DIVERSITY_FLOOR = 0.3;
/**
 * Re-rank a scored candidate pool for answer/concept variety.
 *
 * Pure: returns a new array (diversified order, adjusted scores, appended
 * provenance) and does not mutate the input cards. Cards entering are assumed
 * to have score > 0 (the Pipeline strips zero-score cards before this stage).
 * Non-finite scores (mandatory `requireCards`, score = +Infinity) are emitted
 * untouched and still count toward repetition for later cards.
 *
 * @param cards - Post-filter, post-hint candidates.
 * @param opts  - Optional strength/floor overrides (defaults are sane and
 *                course-general; promote to strategy config if you ever want
 *                this learnable under the orchestration layer).
 * @returns Cards in diversified order with penalised scores.
 */
declare function diversityRerank(cards: WeightedCard[], opts?: DiversityRerankOptions): WeightedCard[];

/**
 * A navigation pipeline that runs a generator and applies filters sequentially.
 *
 * Implements StudyContentSource for backward compatibility with SessionController.
 *
 * ## Usage
 *
 * ```typescript
 * const pipeline = new Pipeline(
 *   compositeGenerator,  // or single generator
 *   [eloDistanceFilter, interferenceFilter],
 *   user,
 *   course
 * );
 *
 * const cards = await pipeline.getWeightedCards(20);
 * ```
 */
/**
 * Narrow capability surface for out-of-band, commit-free reads against a live
 * pipeline (see {@link getActivePipeline}). Kept minimal on purpose — consumers
 * get the forecast capability, not the whole `Pipeline` class.
 */
interface PipelineForecaster {
    forecast(opts?: {
        hints?: ReplanHints;
        unseenOnly?: boolean;
        threshold?: number;
        limit?: number;
    }): Promise<WeightedCard[]>;
}
/**
 * Diagnosis of the full card space for the current user.
 */
interface CardSpaceDiagnosis {
    totalCards: number;
    threshold: number;
    wellIndicated: number;
    encountered: number;
    wellIndicatedNew: number;
    byType: Record<string, {
        total: number;
        wellIndicated: number;
        new: number;
    }>;
    filterBreakdown: Array<{
        name: string;
        wellIndicated: number;
    }>;
    elapsedMs: number;
}

/**
 * The most recently constructed pipeline for the current session, or null if
 * none has been built yet. This is the supported, non-debug accessor for
 * out-of-band reads against the live pipeline (e.g. a commit-free
 * `forecast()`), replacing reach-ins through `window.skuilder.pipeline`.
 */
declare function getActivePipeline(): PipelineForecaster | null;
/**
 * Summary of a single generator's contribution.
 */
interface GeneratorSummary {
    name: string;
    cardCount: number;
    newCount: number;
    reviewCount: number;
    topScore: number;
}
/**
 * Summary of a filter's impact on scores.
 */
interface FilterImpact {
    name: string;
    boosted: number;
    penalized: number;
    passed: number;
    removed: number;
}
/**
 * Complete record of a single pipeline execution.
 */
interface PipelineRunReport {
    runId: string;
    timestamp: Date;
    courseId: string;
    courseName?: string;
    /** User's global ELO at the time of this pipeline run */
    userElo?: number;
    generatorName: string;
    generators?: GeneratorSummary[];
    generatedCount: number;
    filters: FilterImpact[];
    /** Ephemeral hints applied during this run */
    hints?: ReplanHints;
    finalCount: number;
    reviewsSelected: number;
    newSelected: number;
    /**
     * Card data for inspection.
     *
     * To keep the in-memory ring buffer small, this contains:
     *   - All selected cards (the actual session output).
     *   - The top-N highest-scoring non-selected cards (see DISCARDED_KEEP_TOP),
     *     useful for understanding "near misses" and filter behavior.
     *
     * The remaining low-score tail of the candidate pool (mostly ELO-window
     * pull remnants that filters scored down) is summarized in `discardedTail`
     * rather than retained verbatim — each retained card carries a multi-KB
     * provenance trail, and the tail is typically hundreds of cards per run.
     */
    cards: Array<{
        cardId: string;
        courseId: string;
        origin: 'new' | 'review' | 'unknown';
        generator?: string;
        finalScore: number;
        /** Card's ELO (parsed from ELO generator provenance, if available) */
        cardElo?: number;
        provenance: StrategyContribution[];
        tags?: string[];
        selected: boolean;
    }>;
    /**
     * Summary of the discarded tail of the candidate pool — cards that were
     * generated and scored but neither selected nor retained in `cards`.
     *
     * Provides breadcrumbs for "where did card X go?" investigations without
     * the memory cost of keeping every dropped candidate's provenance.
     *
     * Future: may carry a bloom filter of discarded cardIds so callers can
     * ask "was X in this run's discard tail?" with bounded memory cost.
     */
    discardedTail?: {
        count: number;
        /** [min, max] finalScore across the discarded tail. */
        scoreRange?: [number, number];
        /** [min, max] cardElo across the discarded tail (where parseable). */
        eloRange?: [number, number];
        /** Human-readable note for console display. */
        note: string;
    };
}
/**
 * Console API object exposed on window.skuilder.pipeline
 */
declare const pipelineDebugAPI: {
    /**
     * Get raw run history for programmatic access.
     */
    readonly runs: PipelineRunReport[];
    /**
     * Show summary of a specific pipeline run.
     */
    showRun(idOrIndex?: string | number): void;
    /**
     * Show summary of the last pipeline run.
     */
    showLastRun(): void;
    /**
     * Show detailed provenance for a specific card.
     */
    showCard(cardId: string): void;
    /**
     * Explain why reviews may or may not have been selected.
     */
    explainReviews(): void;
    /**
     * Show prescribed-related cards from the most recent run.
     *
     * Highlights:
     * - cards directly generated by the prescribed strategy
     * - blocked prescribed targets mentioned in provenance
     * - support tags resolved for blocked targets
     *
     * @param groupId - Optional prescribed group ID filter (e.g. 'intro-core')
     */
    showPrescribed(groupId?: string): void;
    /**
     * Show all runs in compact format.
     */
    listRuns(): void;
    /**
     * Export run history as JSON for bug reports.
     */
    export(): string;
    /**
     * Clear run history.
     */
    clear(): void;
    /**
     * Show the navigator registry: all registered classes and their roles.
     *
     * Useful for verifying that consumer-defined navigators were registered
     * before pipeline assembly.
     */
    showRegistry(): void;
    /**
     * Show strategy documents from the last pipeline run and how they mapped
     * to the registry.
     *
     * If no runs are captured yet, falls back to showing just the registry.
     */
    showStrategies(): void;
    /**
     * Scan the full card space through the filter chain for the current user.
     *
     * Reports how many cards are well-indicated and how many are new.
     * Use this to understand how the search space grows during onboarding.
     *
     * @param threshold - Score threshold for "well indicated" (default 0.10)
     */
    diagnoseCardSpace(threshold?: number): Promise<CardSpaceDiagnosis | null>;
    /**
     * Show user's per-tag ELO data. Useful for diagnosing hierarchy gate status.
     *
     * @param tagFilter - Optional glob pattern(s) to filter tags.
     *   Examples: 'gpc:expose:*', 'gpc:intro:t-T', ['gpc:expose:t-*', 'gpc:intro:t-*']
     */
    showTagElo(tagFilter?: string | string[]): Promise<void>;
    /**
     * Toggle the full-screen UI debugger.
     */
    ui(): void;
    /**
     * Internal UI helpers
     * @internal
     */
    _selectRun(index: number): void;
    /**
     * Internal UI helpers
     * @internal
     */
    _setSearch(query: string): void;
    /**
     * Internal UI helpers
     * @internal
     */
    _copyConfig(runId: string, btn?: HTMLElement): void;
    /**
     * Internal UI helpers
     * @internal
     *
     * Copies an "abridged" view of results: just the selected cards with their
     * generator, origin, final score, and the top provenance reason. Designed
     * for pasting into bug reports without flooding with full provenance.
     */
    _copyResults(runId: string, btn?: HTMLElement): void;
    /**
     * Show help.
     */
    help(): void;
};
/**
 * Mount the debug API on window.skuilder.pipeline
 */
declare function mountPipelineDebugger(): void;

/**
 * Template literal type for strategy state document IDs.
 *
 * Format: `STRATEGY_STATE-{courseId}-{strategyKey}`
 */
type StrategyStateId = `${(typeof DocTypePrefixes)[DocType.STRATEGY_STATE]}::${string}::${string}`;
/**
 * Document storing strategy-specific state in the user database.
 *
 * Each strategy can persist its own state (user preferences, learned patterns,
 * temporal tracking, etc.) using this document type. The state is scoped to
 * a (user, course, strategy) tuple.
 *
 * ## Use Cases
 *
 * 1. **Explicit user preferences**: User configures tag filters, difficulty
 *    preferences, or learning goals. UI writes to strategy state.
 *
 * 2. **Learned/temporal state**: Strategy tracks patterns over time, e.g.,
 *    "when did I last introduce confusable concepts together?"
 *
 * 3. **Adaptive personalization**: Strategy infers user preferences from
 *    behavior and stores them for future sessions.
 *
 * ## Storage Location
 *
 * These documents live in the **user database**, not the course database.
 * They sync with the user's data across devices.
 *
 * ## Document ID Format
 *
 * `STRATEGY_STATE::{courseId}::{strategyKey}`
 *
 * Example: `STRATEGY_STATE::piano-basics::UserTagPreferenceFilter`
 *
 * @template T - The shape of the strategy-specific data payload
 */
interface StrategyStateDoc<T = unknown> {
    _id: StrategyStateId;
    _rev?: string;
    docType: DocType.STRATEGY_STATE;
    /**
     * The course this state applies to.
     */
    courseId: string;
    /**
     * Unique key identifying the strategy instance.
     * Typically the strategy class name (e.g., "UserTagPreferenceFilter",
     * "InterferenceMitigatorNavigator").
     *
     * If a course has multiple instances of the same strategy type with
     * different configurations, use a more specific key.
     */
    strategyKey: string;
    /**
     * Strategy-specific data payload.
     * Each strategy defines its own schema for this field.
     */
    data: T;
    /**
     * ISO timestamp of last update.
     * Use `moment.utc(updatedAt)` to parse into a Moment object.
     */
    updatedAt: string;
}
/**
 * Build the document ID for a strategy state document.
 *
 * @param courseId - The course ID
 * @param strategyKey - The strategy key (typically class name)
 * @returns The document ID in format `STRATEGY_STATE::{courseId}::{strategyKey}`
 */
declare function buildStrategyStateId(courseId: string, strategyKey: string): StrategyStateId;

declare function areQuestionRecords(h: CardHistory<CardRecord>): h is CardHistory<QuestionRecord>;
declare function isQuestionRecord(c: CardRecord): c is QuestionRecord;
declare function getCardHistoryID(courseID: string, cardID: string): PouchDB.Core.DocumentId;
declare function parseCardHistoryID(id: string): {
    courseID: string;
    cardID: string;
};
interface PouchDBError extends Error {
    error?: string;
    reason?: string;
}
declare function docIsDeleted(e: PouchDBError): boolean;

/**
 * Interface representing the result of a bulk import operation for a single card
 */
interface ImportResult {
    /** The original text input for the card */
    originalText: string;
    /** Status of the import operation */
    status: 'success' | 'error';
    /** Message describing the result or error */
    message: string;
    /** ID of the newly created card (only for success) */
    cardId?: string;
}
/**
 * Configuration for the bulk card processor
 */
interface BulkCardProcessorConfig {
    /** The data shape to use for the cards */
    dataShape: DataShape;
    /** The course code used for adding notes */
    courseCode: string;
    /** The username of the current user */
    userName: string;
}

/**
 * Processes multiple cards from bulk text input
 *
 * @param parsedCards - Array of parsed cards to import
 * @param courseDB - Course database interface
 * @param config - Configuration for the card processor
 * @returns Array of import results
 */
declare function importParsedCards(parsedCards: ParsedCard[], courseDB: CourseDBInterface, config: BulkCardProcessorConfig): Promise<ImportResult[]>;
/**
 * Validates the configuration for bulk card processing
 *
 * @param config - Configuration to validate
 * @returns Object with validation result and error message if any
 */
declare function validateProcessorConfig(config: Partial<BulkCardProcessorConfig>): {
    isValid: boolean;
    errorMessage?: string;
};

/**
 * Console API object exposed on window.skuilder.userdb
 */
declare const userDBDebugAPI: {
    /**
     * Show current user information
     */
    showUser(): void;
    /**
     * Show scheduled reviews
     */
    showScheduledReviews(courseId?: string): Promise<void>;
    /**
     * Show course registrations
     */
    showCourseRegistrations(): Promise<void>;
    /**
     * Show card history for a specific card
     */
    showCardHistory(cardId: string): Promise<void>;
    /**
     * Query documents by type
     */
    queryByType(docType: keyof typeof DocType, limit?: number): Promise<void>;
    /**
     * Show database info and statistics
     */
    dbInfo(): Promise<void>;
    /**
     * List all document types
     */
    listDocTypes(): void;
    /**
     * Export database contents (limited, for debugging)
     */
    export(includeContent?: boolean): Promise<string>;
    /**
     * Execute raw PouchDB query
     */
    raw(queryFn: (db: PouchDB.Database) => Promise<any>): Promise<void>;
    /**
     * Show help
     */
    help(): void;
};
/**
 * Mount the debug API on window.skuilder.userdb
 */
declare function mountUserDBDebugger(): void;

export { type BulkCardProcessorConfig, type CardFilter, type CardFilterFactory, CardHistory, CardRecord, CourseDBInterface, DIVERSITY_FLOOR, DIVERSITY_STRENGTH, type DiversityRerankOptions, DocType, DocTypePrefixes, type FilterContext, type FilterImpact, type GeneratorSummary, type GradientObservation, type GradientResult, type ImportResult, LearnableWeight, Loggable, OrchestrationContext, type PeriodUpdateInput, type PeriodUpdateResult, type PipelineForecaster, type PipelineRunReport, type PressureGaugeDebug, QuestionRecord, ReplanHints, type SignalConfig, type SrsBacklogDebug, StrategyContribution, type StrategyLearningState, type StrategyPressureDebug, type StrategyStateDoc, type StrategyStateId, UserDBInterface, UserOutcomeRecord, WeightedCard, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, captureStrategyPressure, clearSrsBacklogDebug, clearStrategyPressureDebug, computeOutcomeSignal, computeStrategyGradient, diversityRerank, docIsDeleted, getActivePipeline, getCardHistoryID, getDefaultLearnableWeight, getSrsBacklogDebug, getStrategyPressureDebug, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig };
