For AI agents: the complete documentation index is available at https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/llms.txt, the full documentation bundle is available at https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/llms-full.txt, and this page is available as Markdown at https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/guide/migration.md.
  • 简体中文
  • 迁移到 v6 与 FSRS-7

    包版本与模型版本是两件事:ts-fsrs v5 已使用 FSRS-6。先将应用代码和存储记录迁移到 v6 API,继续使用 FSRS-6;再单独迁移模型。本文对应本站的 v6 API,安装时应锁定与本文接口一致的 v6 版本。

    迁移后的代码不得使用 legacy API

    使用 defineScheduler 和明确的模型入口。迁移后的代码不得使用 fsrs()、FSRS、createEmptyCard、generatorParameters、旧调度器类和策略,或根入口导出的旧 Card、CardInput、ReviewLog、FSRSParameters 等 legacy 类型。部分符号仍为兼容而导出,不代表它们是 v6 的接入方式。下文旧名称仅用于静态对照;可运行示例不使用 legacy API 或类型。

    For your Agent
    让 Agent 完成迁移

    复制给有仓库访问权限的 Agent:先确认迁移目标,再梳理变更 TODO List;用户确认清单后才实施与验证。

    1. 迁移到 v6 API,保持 FSRS-6

    定义调度策略

    defineScheduler({ model, chrono }) 创建可复用的定义;.use(...) 组合中间件并返回新定义;.create({ config }) 校验配置并创建独立调度器实例。将定义保留在程序层级,根据用户或牌组配置创建实例。

    裸定义不包含全部 v5 调度策略。下面沿用当前标准预设的中间件顺序:目标保留率、模糊、统计、已调度天数、学习步骤、最大间隔、单调间隔。请保留实际配置和 FSRS-6 权重。使用 dateChrono 时,fractionalDays: false 按 UTC 日历日计算间隔;仅迁移 API 时不要未经验证就同时改变时间策略。

    import { 
    const dateChrono: Chrono<{
        readonly time: SRSSchema<{
            input: Date;
            output: Date;
        }>;
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly fields: {
            readonly card: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                };
            }>;
            readonly revlog: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                    reviewTime: Date;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                    reviewTime: Date;
                };
            }>;
        };
    }>
    dateChrono
    ,
    function defineScheduler<const M extends AnyModel, const C extends AnyChrono>(definition: {
        readonly model: M;
        readonly chrono: C;
    }): CustomScheduler<SchedulerNameOf<M>, SchedulerEnvFor<M, C, readonly []>, M, C>
    defineScheduler
    ,
    type Rating = 0 | 1 | 2 | 3 | 4
    const Rating: Readonly<{
        readonly Manual: 0;
        readonly Again: 1;
        readonly Hard: 2;
        readonly Good: 3;
        readonly Easy: 4;
    }>
    Rating
    ,
    type State = 0 | 1 | 2 | 3
    const State: Readonly<{
        readonly New: 0;
        readonly Learning: 1;
        readonly Review: 2;
        readonly Relearning: 3;
    }>
    State
    } from 'ts-fsrs'
    import {
    const schedulerDesiredRetentionMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly desiredRetention: number | Record<Grade, number>;
            };
            output: {
                readonly desiredRetention: Record<Grade, number>;
            };
        }>;
    }>
    schedulerDesiredRetentionMiddleware
    ,
    const schedulerFuzzingMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays?: boolean;
            };
            output: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays: boolean;
            };
        }>;
        readonly cardInitInput: SRSSchema<{
            input: {
                readonly cardId?: string | number;
            };
            output: {
                readonly cardId?: string | number;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly cardId: string | number;
                readonly reps: number;
            };
            output: {
                readonly cardId: string | number;
                readonly reps: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly cardId: string | number;
            };
            output: {
                readonly cardId: string | number;
            };
        }>;
    }>
    schedulerFuzzingMiddleware
    ,
    const schedulerLearningStepsMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly learningSteps: readonly StepUnit[];
                readonly relearningSteps: readonly StepUnit[];
                readonly enableShortTerm: boolean;
                readonly graduatingInterval?: number;
                readonly allowModelOverride?: boolean;
            };
            output: {
                readonly learningSteps: readonly StepUnit[];
                readonly relearningSteps: readonly StepUnit[];
                readonly enableShortTerm: boolean;
                readonly graduatingInterval: number;
                readonly allowModelOverride: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly learningStep?: number;
            };
            output: {
                readonly learningStep: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly learningStep?: number;
            };
            output: {
                readonly learningStep: number;
            };
        }>;
    }>
    schedulerLearningStepsMiddleware
    ,
    const schedulerMaximumIntervalMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly maximumInterval?: number;
            };
            output: {
                readonly maximumInterval: number;
            };
        }>;
    }>

    Register after learning steps so explicit steps can keep their exact delay.

    schedulerMaximumIntervalMiddleware
    ,
    const schedulerMonotonicIntervalMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly maximumInterval?: number;
            };
            output: {
                readonly maximumInterval: number;
            };
        }>;
    }>

    Register after fuzzing and learning steps, when present.

    schedulerMonotonicIntervalMiddleware
    ,
    const schedulerScheduledDaysMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly scheduledDays: number;
            };
            output: {
                readonly scheduledDays: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly scheduledDays: number;
            };
            output: {
                readonly scheduledDays: number;
            };
        }>;
    }>

    Register before interval middleware so it records their final value on unwind.

    schedulerScheduledDaysMiddleware
    ,
    const schedulerStatsMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly clearStatsOnForget?: boolean | undefined;
            };
            output: {
                readonly clearStatsOnForget: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly reps: number;
                readonly lapses: number;
            };
            output: {
                readonly reps: number;
                readonly lapses: number;
            };
        }>;
    }>
    schedulerStatsMiddleware
    ,
    } from 'ts-fsrs/middlewares' import {
    const FSRS6Model: Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>
    FSRS6Model
    ,
    const migrateFSRS6Parameters: (parameters?: readonly number[]) => number[]
    migrateFSRS6Parameters
    } from 'ts-fsrs/models/fsrs-6'
    // Keep the definition at application scope; create an instance per config. export const
    const definition: CustomScheduler<"fsrs-6", ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>
    definition
    =
    defineScheduler<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>>(definition: {
        ...;
    }): CustomScheduler<...>
    defineScheduler
    ({
    model: Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>
    model
    :
    const FSRS6Model: Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>
    FSRS6Model
    ,
    chrono: Chrono<{
        readonly time: SRSSchema<{
            input: Date;
            output: Date;
        }>;
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly fields: {
            readonly card: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                };
            }>;
            readonly revlog: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                    reviewTime: Date;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                    reviewTime: Date;
                };
            }>;
        };
    }>
    chrono
    :
    const dateChrono: Chrono<{
        readonly time: SRSSchema<{
            input: Date;
            output: Date;
        }>;
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly fields: {
            readonly card: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                };
            }>;
            readonly revlog: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                    reviewTime: Date;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                    reviewTime: Date;
                };
            }>;
        };
    }>
    dateChrono
    ,
    }).
    CustomScheduler<"fsrs-6", SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, Model<...>, Chrono<...>>.use: <readonly [Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly desiredRetention: number | Record<Grade, number>;
            };
            output: {
                readonly desiredRetention: Record<Grade, number>;
            };
        }>;
    }>, Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays?: boolean;
            };
            output: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays: boolean;
            };
        }>;
        readonly cardInitInput: SRSSchema<{
            input: {
                readonly cardId?: string | number;
            };
            output: {
                readonly cardId?: string | number;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly cardId: string | number;
                readonly reps: number;
            };
            output: {
                readonly cardId: string | number;
                readonly reps: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly cardId: string | number;
            };
            output: {
                readonly cardId: string | number;
            };
        }>;
    }>, ... 4 more ..., Middleware<...>]>(middlewares_0: Middleware<...>, middlewares_1: Middleware<...>, middlewares_2: Middleware<...>, middlewares_3: Middleware<...>, middlewares_4: Middleware<...>, middlewares_5: Middleware<...>, middlewares_6: Middleware<...>) => CustomScheduler<...>

    Returns a new scheduler definition extended with the supplied middleware. The current scheduler and any cores created from it remain unchanged.

    use
    (
    const schedulerDesiredRetentionMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly desiredRetention: number | Record<Grade, number>;
            };
            output: {
                readonly desiredRetention: Record<Grade, number>;
            };
        }>;
    }>
    schedulerDesiredRetentionMiddleware
    ,
    const schedulerFuzzingMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays?: boolean;
            };
            output: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays: boolean;
            };
        }>;
        readonly cardInitInput: SRSSchema<{
            input: {
                readonly cardId?: string | number;
            };
            output: {
                readonly cardId?: string | number;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly cardId: string | number;
                readonly reps: number;
            };
            output: {
                readonly cardId: string | number;
                readonly reps: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly cardId: string | number;
            };
            output: {
                readonly cardId: string | number;
            };
        }>;
    }>
    schedulerFuzzingMiddleware
    ,
    const schedulerStatsMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly clearStatsOnForget?: boolean | undefined;
            };
            output: {
                readonly clearStatsOnForget: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly reps: number;
                readonly lapses: number;
            };
            output: {
                readonly reps: number;
                readonly lapses: number;
            };
        }>;
    }>
    schedulerStatsMiddleware
    ,
    const schedulerScheduledDaysMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly scheduledDays: number;
            };
            output: {
                readonly scheduledDays: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly scheduledDays: number;
            };
            output: {
                readonly scheduledDays: number;
            };
        }>;
    }>

    Register before interval middleware so it records their final value on unwind.

    schedulerScheduledDaysMiddleware
    ,
    const schedulerLearningStepsMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly learningSteps: readonly StepUnit[];
                readonly relearningSteps: readonly StepUnit[];
                readonly enableShortTerm: boolean;
                readonly graduatingInterval?: number;
                readonly allowModelOverride?: boolean;
            };
            output: {
                readonly learningSteps: readonly StepUnit[];
                readonly relearningSteps: readonly StepUnit[];
                readonly enableShortTerm: boolean;
                readonly graduatingInterval: number;
                readonly allowModelOverride: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly learningStep?: number;
            };
            output: {
                readonly learningStep: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly learningStep?: number;
            };
            output: {
                readonly learningStep: number;
            };
        }>;
    }>
    schedulerLearningStepsMiddleware
    ,
    const schedulerMaximumIntervalMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly maximumInterval?: number;
            };
            output: {
                readonly maximumInterval: number;
            };
        }>;
    }>

    Register after learning steps so explicit steps can keep their exact delay.

    schedulerMaximumIntervalMiddleware
    ,
    const schedulerMonotonicIntervalMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly maximumInterval?: number;
            };
            output: {
                readonly maximumInterval: number;
            };
        }>;
    }>

    Register after fuzzing and learning steps, when present.

    schedulerMonotonicIntervalMiddleware
    ) export const
    const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
    scheduler
    =
    const definition: CustomScheduler<"fsrs-6", ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>
    definition
    .
    CustomScheduler<"fsrs-6", ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>.create: (ctx: {
        readonly config: Omit<SchedulerConfigInput<Model<{
            readonly name: "fsrs-6";
            readonly config: SRSSchema<{
                input: {
                    readonly weights: number[];
                    readonly enableShortTerm: boolean;
                    readonly numRelearningSteps: number;
                };
                output: {
                    readonly weights: number[];
                    readonly enableShortTerm: boolean;
                    readonly numRelearningSteps: number;
                };
            }>;
            readonly memoryState: SRSSchema<{
                input: {
                    stability: number;
                    difficulty: number;
                };
                output: {
                    stability: number;
                    difficulty: number;
                };
            }>;
            readonly algorithm: FSRS6Algorithm;
        }>, Chrono<...>, readonly []>, "fractionalDays" | ... 8 more ... | "clearStatsOnForget"> & {
            ...;
        };
    }) => SchedulerCore<...>
    create
    ({
    config: Omit<SchedulerConfigInput<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>, readonly []>, "fractionalDays" | ... 8 more ... | "clearStatsOnForget"> & {
        ...;
    }
    config
    : {
    weights:
    function migrateFSRS6Parameters(parameters?: readonly number[]): number[]
    migrateFSRS6Parameters
    (), // Pass the user's existing FSRS-6 weights here.
    fractionalDays: false, enableShortTerm: true, numRelearningSteps: 1, // Keep equal to relearningSteps.length. desiredRetention: 0.9, learningSteps: ['1m', '10m'], relearningSteps: ['10m'], enableFuzz: false, maximumInterval: 36500, clearStatsOnForget: false, // Match v5 forget's default counter behavior. }, }) export type
    type Card = {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    Card
    = ReturnType<typeof
    const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
    scheduler
    .
    SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.newCard: (options?: (Omit<{
        readonly now?: Date | undefined;
    } & {
        readonly cardId?: string | number | undefined;
    }, "now"> & {
        readonly now?: Date | undefined;
    }) | undefined) => {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    newCard
    >
    export type
    type Revlog = {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        learningStep: number;
        scheduledDays: number;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    }
    Revlog
    = ReturnType<typeof
    const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
    scheduler
    .
    SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.review: (input: {
        readonly card: Readonly<Omit<Readonly<Omit<Readonly<{
            stability: number;
            difficulty: number;
        } & {
            dueAt: Date;
            lastReviewAt: Date | null;
        } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
            readonly cardId: string | number;
            readonly reps: number;
            readonly learningStep?: number | undefined;
            readonly scheduledDays: number;
            readonly lapses: number;
        }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>, keyof SchedulerCoreFields$1<...>> & SchedulerCoreFields$1<...>>;
        readonly grade: Grade;
        readonly now?: Date | undefined;
    }) => {
        ...;
    }
    review
    >['revlog']
    // An application's stored v5 record, not a legacy library type. type
    type StoredV5Card = {
        due: string;
        last_review?: string | null;
        stability: number;
        difficulty: number;
        state: State;
        scheduled_days: number;
        learning_steps: number;
        reps: number;
        lapses: number;
    }
    StoredV5Card
    = {
    due: string last_review?: string | null stability: number difficulty: number state:
    type State = 0 | 1 | 2 | 3
    State
    scheduled_days: number learning_steps: number reps: number lapses: number } export function
    function convertCard(stored: StoredV5Card, cardId: Card["cardId"]): Card
    convertCard
    (
    stored:
    type StoredV5Card = {
        due: string;
        last_review?: string | null;
        stability: number;
        difficulty: number;
        state: State;
        scheduled_days: number;
        learning_steps: number;
        reps: number;
        lapses: number;
    }
    StoredV5Card
    ,
    cardId:
    type Card = {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    Card
    ['cardId']
    ):
    type Card = {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    Card
    {
    const scheduleStatus = { [
    const State: Readonly<{
        readonly New: 0;
        readonly Learning: 1;
        readonly Review: 2;
        readonly Relearning: 3;
    }>
    State
    .New]: 'new',
    [
    const State: Readonly<{
        readonly New: 0;
        readonly Learning: 1;
        readonly Review: 2;
        readonly Relearning: 3;
    }>
    State
    .Learning]: 'learning',
    [
    const State: Readonly<{
        readonly New: 0;
        readonly Learning: 1;
        readonly Review: 2;
        readonly Relearning: 3;
    }>
    State
    .Review]: 'review',
    [
    const State: Readonly<{
        readonly New: 0;
        readonly Learning: 1;
        readonly Review: 2;
        readonly Relearning: 3;
    }>
    State
    .Relearning]: 'learning',
    } as const return
    const definition: CustomScheduler<"fsrs-6", ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>
    definition
    .
    CustomScheduler<"fsrs-6", ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>.schema: SchedulerSchema<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>
    schema
    .
    SchedulerSchema<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>.card: SRSSchema<{
        input: Readonly<Omit<Readonly<{
            stability: number;
            difficulty: number;
        } & {
            dueAt: Date;
            lastReviewAt: Date | null;
        } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
            readonly cardId: string | number;
            readonly reps: number;
            readonly learningStep?: number | undefined;
            readonly scheduledDays: number;
            readonly lapses: number;
        }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>;
        output: Mutable<...>;
    }>
    card
    .
    SRSSchema<{ input: Readonly<Omit<Readonly<{ stability: number; difficulty: number; } & { dueAt: Date; lastReviewAt: Date | null; } & SchedulerCoreFields$1<"new" | "learning" | "review">> & { ...; }, keyof SchedulerCoreFields$1<...>> & SchedulerCoreFields$1<...>>; output: Mutable<...>; }>.parse(input: unknown): Mutable<Omit<Mutable<{
        stability: number;
        difficulty: number;
    } & {
        dueAt: Date;
        lastReviewAt: Date | null;
    } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
        readonly cardId: string | number;
        readonly reps: number;
        readonly learningStep: number;
        readonly scheduledDays: number;
        readonly lapses: number;
    }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>
    parse
    ({
    cardId, dueAt: new Date(stored.due), lastReviewAt: stored.state ===
    const State: Readonly<{
        readonly New: 0;
        readonly Learning: 1;
        readonly Review: 2;
        readonly Relearning: 3;
    }>
    State
    .New || stored.last_review == null
    ? null : new Date(stored.last_review), stability: stored.stability, difficulty: stored.difficulty, state: stored.state, scheduleStatus: scheduleStatus[stored.state], scheduledDays: stored.scheduled_days, learningStep: stored.learning_steps, reps: stored.reps, lapses: stored.lapses, }) } export const storedCard = { due: '2026-01-03T00:00:00.000Z', last_review: '2026-01-01T00:00:00.000Z', stability: 2, difficulty: 5, state:
    const State: Readonly<{
        readonly New: 0;
        readonly Learning: 1;
        readonly Review: 2;
        readonly Relearning: 3;
    }>
    State
    .Review,
    scheduled_days: 2, learning_steps: 0, reps: 3, lapses: 0, } satisfies
    type StoredV5Card = {
        due: string;
        last_review?: string | null;
        stability: number;
        difficulty: number;
        state: State;
        scheduled_days: number;
        learning_steps: number;
        reps: number;
        lapses: number;
    }
    StoredV5Card
    const
    const card: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    card
    =
    function convertCard(stored: StoredV5Card, cardId: Card["cardId"]): Card
    convertCard
    (storedCard, 'card-1')
    // An overdue review: previous review, original due date and now are distinct. const now = new Date('2026-01-04T00:00:00.000Z') const
    const result: {
        card: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            reps: number;
            learningStep: number;
            scheduledDays: number;
            lapses: number;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
        };
        revlog: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            learningStep: number;
            scheduledDays: number;
            reviewTime: Date;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
            rating: Grade;
        };
    }
    result
    =
    const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
    scheduler
    .
    SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.review: (input: {
        readonly card: Readonly<Omit<Readonly<Omit<Readonly<{
            stability: number;
            difficulty: number;
        } & {
            dueAt: Date;
            lastReviewAt: Date | null;
        } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
            readonly cardId: string | number;
            readonly reps: number;
            readonly learningStep?: number | undefined;
            readonly scheduledDays: number;
            readonly lapses: number;
        }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>, keyof SchedulerCoreFields$1<...>> & SchedulerCoreFields$1<...>>;
        readonly grade: Grade;
        readonly now?: Date | undefined;
    }) => {
        ...;
    }
    review
    ({ card, grade:
    const Rating: Readonly<{
        readonly Manual: 0;
        readonly Again: 1;
        readonly Hard: 2;
        readonly Good: 3;
        readonly Easy: 4;
    }>
    Rating
    .Good, now })
    const
    const restored: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    restored
    =
    const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-6";
        readonly config: SRSSchema<{
            input: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
            output: {
                readonly weights: number[];
                readonly enableShortTerm: boolean;
                readonly numRelearningSteps: number;
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stability: number;
                difficulty: number;
            };
            output: {
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS6Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
    scheduler
    .
    SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.rollback: (input: {
        readonly card: Mutable<Omit<Mutable<Omit<Mutable<{
            stability: number;
            difficulty: number;
        } & {
            dueAt: Date;
            lastReviewAt: Date | null;
        } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
            readonly cardId: string | number;
            readonly reps: number;
            readonly learningStep: number;
            readonly scheduledDays: number;
            readonly lapses: number;
        }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>, keyof SchedulerCoreFields$1<...>> & SchedulerCoreFields$1<...>>;
        readonly revlog: Mutable<...>;
    }) => {
        ...;
    }
    rollback
    ({
    card: Mutable<Omit<Mutable<Omit<Mutable<{
        stability: number;
        difficulty: number;
    } & {
        dueAt: Date;
        lastReviewAt: Date | null;
    } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
        readonly cardId: string | number;
        readonly reps: number;
        readonly learningStep: number;
        readonly scheduledDays: number;
        readonly lapses: number;
    }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>, keyof SchedulerCoreFields$1<...>> & SchedulerCoreFields$1<...>>
    card
    :
    const result: {
        card: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            reps: number;
            learningStep: number;
            scheduledDays: number;
            lapses: number;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
        };
        revlog: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            learningStep: number;
            scheduledDays: number;
            reviewTime: Date;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
            rating: Grade;
        };
    }
    result
    .
    card: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    card
    ,
    revlog: Mutable<Omit<Mutable<Omit<Mutable<{
        stability: number;
        difficulty: number;
    } & {
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
    } & SchedulerCoreFields$1<"new" | "learning" | "review"> & {
        readonly rating: Grade;
    }> & {
        readonly cardId: string | number;
        readonly learningStep: number;
        readonly scheduledDays: number;
    }, "rating" | keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review"> & {
        readonly rating: Grade;
    }>, "rating" | keyof SchedulerCoreFields$1<...>> & SchedulerCoreFields$1<...> & {
        readonly rating: Grade;
    }>
    revlog
    :
    const result: {
        card: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            reps: number;
            learningStep: number;
            scheduledDays: number;
            lapses: number;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
        };
        revlog: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            learningStep: number;
            scheduledDays: number;
            reviewTime: Date;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
            rating: Grade;
        };
    }
    result
    .
    revlog: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        learningStep: number;
        scheduledDays: number;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    }
    revlog
    ,
    }) console.log( JSON.stringify( { cardId:
    const result: {
        card: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            reps: number;
            learningStep: number;
            scheduledDays: number;
            lapses: number;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
        };
        revlog: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            learningStep: number;
            scheduledDays: number;
            reviewTime: Date;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
            rating: Grade;
        };
    }
    result
    .
    card: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    card
    .cardId,
    rating:
    const result: {
        card: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            reps: number;
            learningStep: number;
            scheduledDays: number;
            lapses: number;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
        };
        revlog: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            learningStep: number;
            scheduledDays: number;
            reviewTime: Date;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
            rating: Grade;
        };
    }
    result
    .
    revlog: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        learningStep: number;
        scheduledDays: number;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    }
    revlog
    .rating,
    reps:
    const result: {
        card: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            reps: number;
            learningStep: number;
            scheduledDays: number;
            lapses: number;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
        };
        revlog: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            learningStep: number;
            scheduledDays: number;
            reviewTime: Date;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
            rating: Grade;
        };
    }
    result
    .
    card: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    card
    .reps,
    revlog: { lastReviewAt:
    const result: {
        card: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            reps: number;
            learningStep: number;
            scheduledDays: number;
            lapses: number;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
        };
        revlog: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            learningStep: number;
            scheduledDays: number;
            reviewTime: Date;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
            rating: Grade;
        };
    }
    result
    .
    revlog: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        learningStep: number;
        scheduledDays: number;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    }
    revlog
    .lastReviewAt,
    dueAt:
    const result: {
        card: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            reps: number;
            learningStep: number;
            scheduledDays: number;
            lapses: number;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
        };
        revlog: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            learningStep: number;
            scheduledDays: number;
            reviewTime: Date;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
            rating: Grade;
        };
    }
    result
    .
    revlog: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        learningStep: number;
        scheduledDays: number;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    }
    revlog
    .dueAt,
    reviewTime:
    const result: {
        card: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            reps: number;
            learningStep: number;
            scheduledDays: number;
            lapses: number;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
        };
        revlog: {
            cardId: string | number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            learningStep: number;
            scheduledDays: number;
            reviewTime: Date;
            state: State;
            scheduleStatus: "new" | "learning" | "review";
            rating: Grade;
        };
    }
    result
    .
    revlog: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        learningStep: number;
        scheduledDays: number;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    }
    revlog
    .reviewTime,
    }, rollbackDueAt:
    const restored: {
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    restored
    .dueAt,
    }, null, 2 ) )

    局部类型 StoredV5Card 描述应用存储格式,并非从 legacy 库导入。将数据库现有稳定 ID 作为 cardId,应用自有字段单独保留。组合后的卡片 schema 会校验转换后的日期和字段;其他应用字段也应在存储读取边界校验。

    配置对照

    v5 配置v6 配置迁移说明
    wweights此阶段保留用户的 FSRS-6 权重;示例为方便运行才使用默认值。
    request_retentiondesiredRetention需要目标保留率中间件。
    maximum_intervalmaximumInterval需要最大间隔中间件;单调间隔策略也使用此上限。
    enable_fuzzenableFuzz需要模糊中间件,保留旧设置。
    enable_short_termenableShortTerm对 FSRS-6,同时影响模型短期行为和显式学习步骤。
    learning_steps / relearning_stepslearningSteps / relearningSteps保留配置的步骤数组和已有学习进度。
    重新学习步骤数量numRelearningStepsFSRS-6 需设为 relearningSteps.length。
    forget(..., reset_count)clearStatsOnForget改为实例配置;v5 默认 false,v6 统计中间件默认 true。

    卡片、日志与操作

    v5 存储字段v6 字段或处理方式
    due卡片 dueAt,反序列化为 Date。
    elapsed_days / 日志 last_elapsed_days已移除,使用所选 chrono 从时间戳计算经过天数;FSRS-7 重放不要使用这些旧的取整值。
    last_reviewlastReviewAt,缺失或 null 统一为 null。
    scheduled_daysscheduledDays,由中间件提供。
    learning_stepslearningStep,由中间件提供。
    stability、difficulty、state、reps、lapsesAPI 迁移时保留;统计字段需要中间件。
    应用记录 IDcardId,卡片和日志使用同一 ID。
    无对应字段scheduleStatus:New → new,Learning/Relearning → learning,Review → review。
    复习日志 reviewreviewTime,即实际复习时间,不是卡片到期时间。
    结果 { card, log }{ card, revlog }。

    像示例一样从调度器推导类型。卡片和日志字段取决于所选模型、chrono 和中间件。自定义 v5 策略需改写为相应的中间件 hook,不能仅改名或继续继承旧调度器。

    v5 操作(仅供对照)v6 操作
    createEmptyCard(now)scheduler.newCard({ now, cardId })
    f.next(card, now, grade)scheduler.review({ card, now, grade })
    f.repeat(card, now)scheduler.preview({ card, now }) 返回可迭代对象,通过 Symbol.iterator 提供 iterator,可用 for...of 遍历。每个候选项包含 { grade, card, revlog },通过 candidate.grade 选择,不再按评分键索引对象。
    f.rollback(card, log)scheduler.rollback({ card, revlog }),使用返回的 v6 日志。
    f.forget(card, now, reset_count)scheduler.forget({ card, now });返回卡片,不是 { card, log },手动操作日志由应用记录。
    f.get_retrievability(card, now, false)对有 lastReviewAt 的已学习卡片,调用 scheduler.model.forgettingCurve(card, scheduler.chrono.difference(card.lastReviewAt, now)),返回数值;新卡片单独处理,百分比由应用格式化。

    review() 返回新数据,应同时持久化 result.card 和 result.revlog。新日志保存撤销所需的复习前字段,包括 dueAt、lastReviewAt。不能将旧日志的 due 简单改名就用于 v6 撤销:旧日志可能缺少必要的复习前快照。保留原始历史记录,仅转换评分和实际复习时间用于模型重放。跨版本撤销需要独立的应用快照或撤销边界。

    即使模型和配置相同,也不保证所有学习步骤或模糊场景的间隔与 v5 完全一致。切换写入前应检查 New、Learning、Review、Relearning 的代表卡片。DefaultScheduler 是另一种预设入口,但默认模型为 FSRS-7;若在此阶段采用它,应明确指定 FSRS-6。

    为什么日志中的三个时间不能直接改名

    dateChrono 的字段名是 reviewTime,不是 reviewAt。以逾期复习为例:卡片上次在 1 月 1 日复习,原定 1 月 3 日到期,实际在 1 月 4 日复习。

    含义v5 普通复习日志v6 revlog
    上次复习时间:1 月 1 日due(旧实现写入 card.last_review || card.due)lastReviewAt
    原定到期时间:1 月 3 日对此已学习卡片没有单独记录dueAt
    本次实际复习时间:1 月 4 日reviewreviewTime

    lastReviewAt 表示本次复习之前的上次复习时间,输入与输出的类型有所区别:

    • 输入 DateRevlogInputFields 中是可选的 lastReviewAt?: Date | null。省略或传入 undefined 时,schema 会将其规范化为 null;dueAt 和 reviewTime 仍必须是有效的 Date。
    • 输出 DateRevlogFields 中始终存在 lastReviewAt: Date | null。正常的已学习卡片日志记录复习前的 card.lastReviewAt;没有上次复习的新卡片,首次复习日志中的值为 null。
    • null 不会自动推算出缺失的上次复习时间。旧日志缺少该信息时,能通过 schema 校验不等于能精确撤销;不要用 dueAt 或 reviewTime 代替它。

    复习返回的卡片中,lastReviewAt 已变为 1 月 4 日,dueAt 是新计算的到期时间;日志保存的是复习前的时间。使用这张卡片和 v6 日志撤销后,dueAt 恢复为 1 月 3 日,lastReviewAt 恢复为 1 月 1 日,提前或逾期复习也一样。这正是 chrono 重构时分离「计算经过天数的时间」与「供撤销恢复的原到期时间」的原因。上面的可运行示例会打印这三个字段。

    不能统一执行 oldLog.due → revlog.dueAt:普通 v5 已学习卡片日志的 due 通常是上次复习时间;无 last_review 的首次复习日志才存原到期时间,Manual/遗忘日志又有自己的语义。v5 重置后的 New 卡片还可能携带旧 last_review,因此卡片转换示例对 State.New 统一输出 lastReviewAt: null。

    只重建模型记忆时,仅映射 rating 和 review → reviewTime 即可。若要跨版本精确撤销,需要原始复习前卡片快照(包括两个时间字段及中间件字段),否则应设立撤销边界。不能用 review 或重新计算的间隔补造过去未记录的到期时间,尤其是在提前复习、学习步骤、模糊或手动调整之后。

    2. 从 FSRS-6 迁移到 FSRS-7

    权重和状态属于各自的模型

    FSRS-6 使用 21 个权重,FSRS-7 需要独立的 34 个权重。使用 FSRS7_DEFAULT_WEIGHTS,或重新训练 FSRS-7 权重。不要给 FSRS-6 参数补值,也不要复用其训练权重。migrateFSRS7Parameters 仅为空输入提供默认值,不会转换旧模型的参数布局。

    FSRS-7 记忆状态包含 stability、stabilityFast 和 difficulty,三个字段都应通过历史重建。重建结果只用于更新当前 card 的记忆状态(memoryState);历史 revlog 仅作为只读输入,不得修改、覆盖或补写其中的任何数据,包括过去记录的记忆状态。

    不得为已有卡片直接设置 stabilityFast = 0.8 * stability,也不能保留 FSRS-6 的稳定性、难度后只追加快分量。模型初始化使用的系数不是已演化记忆状态的迁移公式。

    设置 fractionalDays: true,保留两次复习相隔十分钟等小数天数。FSRS-7 的快轨迹是模型固有部分:安装学习步骤中间件后,enableShortTerm: false 仅关闭显式学习步骤,不会关闭快轨迹。FSRS-7 模型没有与 FSRS-6 的 numRelearningSteps 对应的配置项。

    FSRS-7 的默认步骤与学习状态

    DefaultScheduler 对 FSRS-7 与 FSRS-3~6 一样默认使用学习步骤 ['1m', '10m'] 与重新学习步骤 ['10m'],并开启 allowModelOverride,让更长的模型间隔覆盖当前步骤。显式传入的步骤不会被默认值覆盖。enableShortTerm 仍默认 true,控制显式步骤,不控制 FSRS-7 快轨迹或按间隔划分的学习状态。

    注册 schedulerLearningStepsMiddleware 后,状态由最终调度间隔决定,即使步骤关闭、为空或已完成:

    复习前状态最终间隔小于 graduatingInterval(默认一天)最终间隔至少 graduatingInterval
    New / LearningLearning,scheduleStatus: learningReview,scheduleStatus: review
    Review / RelearningRelearning,scheduleStatus: learningReview,scheduleStatus: review

    配置了步骤时,没有适用步骤的 Hard、Good、Easy 至少在 graduatingInterval 之后到期,因此走完步骤,以及 Review 卡片按 Hard、Good 或 Easy,都会进入 Review。开启 allowModelOverride 时,使用模型间隔的 Again 总是进入 Learning/Relearning,即使其间隔被限制为 graduatingInterval。

    没有配置步骤时,不能假定「没有 Learning」「只有 Again 才进入 Relearning」或「Easy 一定进入 Review」。一般来说,Easy 跳过显式步骤,Good 仅在存在适用的下一步骤时推进,时长为 0 的步骤视为没有步骤。learningStep 只在卡片留在 Learning/Relearning 时保留下一步骤,卡片进入 Review 时重置为 0;它是步骤索引,不是复习次数。

    这些转换属于中间件,不属于 FSRS7Model。只组合模型和 chrono 的裸调度器仍返回 Review,即使间隔小于一天。迁移应用队列、状态筛选和统计时,需要同步调整依赖旧行为的判断。

    “重放记忆,保留调度安排”一节的完整迁移示例显式保留已有学习步骤,没有依赖默认值。若产品决定完全采用模型驱动的步骤,可明确配置 learningSteps: []、relearningSteps: [];这不等于移除学习步骤中间件。改变步骤策略应单独验证,不能当作卡片字段迁移顺便执行。

    迁移回忆概率调用

    使用 scheduler.model.forgettingCurve(state, elapsedDays) 获取数值回忆概率,或 scheduler.model.algorithm.curve(elapsedDays, state) 检查快慢分量。两者均需完整 FSRS-7 状态:stability、stabilityFast、difficulty,不能只传 FSRS-6 的单个稳定性值。

    也可以从 ts-fsrs/models/fsrs-7 导入独立函数 curve,调用 curve(weights, elapsedDays, state),无需创建算法实例;其中 weights 必须是有效的 34 个 FSRS-7 权重。该函数不执行权重校验:对存储或用户输入先做 schema/参数校验,不要用它探测权重是否有效。使用已迁移的记忆状态与同一份 FSRS-7 权重,elapsedDays 保留小数天数。

    曲线结果包括 retrievability、derivative、fast、slow、fastWeight、slowWeight 和 total;total = fastWeight + slowWeight 是混合系数之和,不是总回忆概率。替代旧回忆概率调用时读取 retrievability,百分比由应用格式化。算法实例的曲线结果也包含 total。这些曲线接口只计算概率与分量,不迁移卡片、生成日志或安排到期时间。

    重放记忆,保留调度安排

    下面是独立可运行示例。它接收已转换为 v6 结构的 FSRS-6 卡片,将存储日志的 review 转成 reviewTime,调用 Reschedule.replay(),不传入旧模型的 initialState。迁移时只重建记忆状态,不重新安排已有卡片的下次复习时间(dueAt)。之后用户复习该卡片时,再由 FSRS-7 计算新的下次复习时间。ID、上次复习时间、学习进度与统计也保持不变。

    import { 
    const dateChrono: Chrono<{
        readonly time: SRSSchema<{
            input: Date;
            output: Date;
        }>;
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly fields: {
            readonly card: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                };
            }>;
            readonly revlog: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                    reviewTime: Date;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                    reviewTime: Date;
                };
            }>;
        };
    }>
    dateChrono
    ,
    function defineScheduler<const M extends AnyModel, const C extends AnyChrono>(definition: {
        readonly model: M;
        readonly chrono: C;
    }): CustomScheduler<SchedulerNameOf<M>, SchedulerEnvFor<M, C, readonly []>, M, C>
    defineScheduler
    ,
    type Rating = 0 | 1 | 2 | 3 | 4
    const Rating: Readonly<{
        readonly Manual: 0;
        readonly Again: 1;
        readonly Hard: 2;
        readonly Good: 3;
        readonly Easy: 4;
    }>
    Rating
    ,
    type State = 0 | 1 | 2 | 3
    const State: Readonly<{
        readonly New: 0;
        readonly Learning: 1;
        readonly Review: 2;
        readonly Relearning: 3;
    }>
    State
    } from 'ts-fsrs'
    import {
    const schedulerDesiredRetentionMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly desiredRetention: number | Record<Grade, number>;
            };
            output: {
                readonly desiredRetention: Record<Grade, number>;
            };
        }>;
    }>
    schedulerDesiredRetentionMiddleware
    ,
    const schedulerFuzzingMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays?: boolean;
            };
            output: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays: boolean;
            };
        }>;
        readonly cardInitInput: SRSSchema<{
            input: {
                readonly cardId?: string | number;
            };
            output: {
                readonly cardId?: string | number;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly cardId: string | number;
                readonly reps: number;
            };
            output: {
                readonly cardId: string | number;
                readonly reps: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly cardId: string | number;
            };
            output: {
                readonly cardId: string | number;
            };
        }>;
    }>
    schedulerFuzzingMiddleware
    ,
    const schedulerLearningStepsMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly learningSteps: readonly StepUnit[];
                readonly relearningSteps: readonly StepUnit[];
                readonly enableShortTerm: boolean;
                readonly graduatingInterval?: number;
                readonly allowModelOverride?: boolean;
            };
            output: {
                readonly learningSteps: readonly StepUnit[];
                readonly relearningSteps: readonly StepUnit[];
                readonly enableShortTerm: boolean;
                readonly graduatingInterval: number;
                readonly allowModelOverride: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly learningStep?: number;
            };
            output: {
                readonly learningStep: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly learningStep?: number;
            };
            output: {
                readonly learningStep: number;
            };
        }>;
    }>
    schedulerLearningStepsMiddleware
    ,
    const schedulerMaximumIntervalMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly maximumInterval?: number;
            };
            output: {
                readonly maximumInterval: number;
            };
        }>;
    }>

    Register after learning steps so explicit steps can keep their exact delay.

    schedulerMaximumIntervalMiddleware
    ,
    const schedulerMonotonicIntervalMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly maximumInterval?: number;
            };
            output: {
                readonly maximumInterval: number;
            };
        }>;
    }>

    Register after fuzzing and learning steps, when present.

    schedulerMonotonicIntervalMiddleware
    ,
    const schedulerScheduledDaysMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly scheduledDays: number;
            };
            output: {
                readonly scheduledDays: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly scheduledDays: number;
            };
            output: {
                readonly scheduledDays: number;
            };
        }>;
    }>

    Register before interval middleware so it records their final value on unwind.

    schedulerScheduledDaysMiddleware
    ,
    const schedulerStatsMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly clearStatsOnForget?: boolean | undefined;
            };
            output: {
                readonly clearStatsOnForget: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly reps: number;
                readonly lapses: number;
            };
            output: {
                readonly reps: number;
                readonly lapses: number;
            };
        }>;
    }>
    schedulerStatsMiddleware
    ,
    } from 'ts-fsrs/middlewares' import {
    const FSRS7_DEFAULT_WEIGHTS: number[]
    FSRS7_DEFAULT_WEIGHTS
    ,
    const FSRS7Model: Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>
    FSRS7Model
    } from 'ts-fsrs/models/fsrs-7'
    import {
    class Reschedule<Scheduler extends AnySchedulerCore>

    Replays a review history on top of an existing srs-kit scheduler core.

    The scheduler instance keeps the model and chronology coupled, allowing the review-time, card and memory-state types to be inferred from the selected core.

    Reschedule
    } from 'ts-fsrs/reschedule'
    export const
    const definition: CustomScheduler<"fsrs-7", ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>
    definition
    =
    defineScheduler<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>>(definition: {
        ...;
    }): CustomScheduler<...>
    defineScheduler
    ({
    model: Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>
    model
    :
    const FSRS7Model: Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>
    FSRS7Model
    ,
    chrono: Chrono<{
        readonly time: SRSSchema<{
            input: Date;
            output: Date;
        }>;
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly fields: {
            readonly card: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                };
            }>;
            readonly revlog: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                    reviewTime: Date;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                    reviewTime: Date;
                };
            }>;
        };
    }>
    chrono
    :
    const dateChrono: Chrono<{
        readonly time: SRSSchema<{
            input: Date;
            output: Date;
        }>;
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly fields: {
            readonly card: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                };
            }>;
            readonly revlog: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                    reviewTime: Date;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                    reviewTime: Date;
                };
            }>;
        };
    }>
    dateChrono
    ,
    }).
    CustomScheduler<"fsrs-7", SchedulerEnvFor<Model<{ readonly name: "fsrs-7"; readonly config: SRSSchema<{ input: { readonly weights: readonly number[]; }; output: { readonly weights: readonly number[]; }; }>; readonly memoryState: SRSSchema<{ input: { stabilityFast: number; stability: number; difficulty: number; }; output: { stabilityFast: number; stability: number; difficulty: number; }; }>; readonly algorithm: FSRS7Algorithm; }>, Chrono<...>, readonly []>, Model<...>, Chrono<...>>.use: <readonly [Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly desiredRetention: number | Record<Grade, number>;
            };
            output: {
                readonly desiredRetention: Record<Grade, number>;
            };
        }>;
    }>, Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays?: boolean;
            };
            output: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays: boolean;
            };
        }>;
        readonly cardInitInput: SRSSchema<{
            input: {
                readonly cardId?: string | number;
            };
            output: {
                readonly cardId?: string | number;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly cardId: string | number;
                readonly reps: number;
            };
            output: {
                readonly cardId: string | number;
                readonly reps: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly cardId: string | number;
            };
            output: {
                readonly cardId: string | number;
            };
        }>;
    }>, ... 4 more ..., Middleware<...>]>(middlewares_0: Middleware<...>, middlewares_1: Middleware<...>, middlewares_2: Middleware<...>, middlewares_3: Middleware<...>, middlewares_4: Middleware<...>, middlewares_5: Middleware<...>, middlewares_6: Middleware<...>) => CustomScheduler<...>

    Returns a new scheduler definition extended with the supplied middleware. The current scheduler and any cores created from it remain unchanged.

    use
    (
    const schedulerDesiredRetentionMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly desiredRetention: number | Record<Grade, number>;
            };
            output: {
                readonly desiredRetention: Record<Grade, number>;
            };
        }>;
    }>
    schedulerDesiredRetentionMiddleware
    ,
    const schedulerFuzzingMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays?: boolean;
            };
            output: {
                readonly enableFuzz: boolean;
                readonly maximumInterval: number;
                readonly fractionalDays: boolean;
            };
        }>;
        readonly cardInitInput: SRSSchema<{
            input: {
                readonly cardId?: string | number;
            };
            output: {
                readonly cardId?: string | number;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly cardId: string | number;
                readonly reps: number;
            };
            output: {
                readonly cardId: string | number;
                readonly reps: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly cardId: string | number;
            };
            output: {
                readonly cardId: string | number;
            };
        }>;
    }>
    schedulerFuzzingMiddleware
    ,
    const schedulerStatsMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly clearStatsOnForget?: boolean | undefined;
            };
            output: {
                readonly clearStatsOnForget: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly reps: number;
                readonly lapses: number;
            };
            output: {
                readonly reps: number;
                readonly lapses: number;
            };
        }>;
    }>
    schedulerStatsMiddleware
    ,
    const schedulerScheduledDaysMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly scheduledDays: number;
            };
            output: {
                readonly scheduledDays: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly scheduledDays: number;
            };
            output: {
                readonly scheduledDays: number;
            };
        }>;
    }>

    Register before interval middleware so it records their final value on unwind.

    schedulerScheduledDaysMiddleware
    ,
    const schedulerLearningStepsMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly learningSteps: readonly StepUnit[];
                readonly relearningSteps: readonly StepUnit[];
                readonly enableShortTerm: boolean;
                readonly graduatingInterval?: number;
                readonly allowModelOverride?: boolean;
            };
            output: {
                readonly learningSteps: readonly StepUnit[];
                readonly relearningSteps: readonly StepUnit[];
                readonly enableShortTerm: boolean;
                readonly graduatingInterval: number;
                readonly allowModelOverride: boolean;
            };
        }>;
        readonly card: SRSSchema<{
            input: {
                readonly learningStep?: number;
            };
            output: {
                readonly learningStep: number;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                readonly learningStep?: number;
            };
            output: {
                readonly learningStep: number;
            };
        }>;
    }>
    schedulerLearningStepsMiddleware
    ,
    const schedulerMaximumIntervalMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly maximumInterval?: number;
            };
            output: {
                readonly maximumInterval: number;
            };
        }>;
    }>

    Register after learning steps so explicit steps can keep their exact delay.

    schedulerMaximumIntervalMiddleware
    ,
    const schedulerMonotonicIntervalMiddleware: Middleware<symbol, {
        readonly config: SRSSchema<{
            input: {
                readonly maximumInterval?: number;
            };
            output: {
                readonly maximumInterval: number;
            };
        }>;
    }>

    Register after fuzzing and learning steps, when present.

    schedulerMonotonicIntervalMiddleware
    ) export const
    const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
    scheduler
    =
    const definition: CustomScheduler<"fsrs-7", ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>
    definition
    .
    CustomScheduler<"fsrs-7", ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-7"; readonly config: SRSSchema<{ input: { readonly weights: readonly number[]; }; output: { readonly weights: readonly number[]; }; }>; readonly memoryState: SRSSchema<{ input: { stabilityFast: number; stability: number; difficulty: number; }; output: { stabilityFast: number; stability: number; difficulty: number; }; }>; readonly algorithm: FSRS7Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>.create: (ctx: {
        readonly config: Omit<SchedulerConfigInput<Model<{
            readonly name: "fsrs-7";
            readonly config: SRSSchema<{
                input: {
                    readonly weights: readonly number[];
                };
                output: {
                    readonly weights: readonly number[];
                };
            }>;
            readonly memoryState: SRSSchema<{
                input: {
                    stabilityFast: number;
                    stability: number;
                    difficulty: number;
                };
                output: {
                    stabilityFast: number;
                    stability: number;
                    difficulty: number;
                };
            }>;
            readonly algorithm: FSRS7Algorithm;
        }>, Chrono<...>, readonly []>, "fractionalDays" | ... 8 more ... | "clearStatsOnForget"> & {
            ...;
        };
    }) => SchedulerCore<...>
    create
    ({
    config: Omit<SchedulerConfigInput<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, "fractionalDays" | ... 8 more ... | "clearStatsOnForget"> & {
        ...;
    }
    config
    : {
    weights:
    const FSRS7_DEFAULT_WEIGHTS: number[]
    FSRS7_DEFAULT_WEIGHTS
    ,
    fractionalDays: true, enableShortTerm: true, // Controls learning steps, not the model's fast trace. desiredRetention: 0.9, // Preserve existing steps explicitly instead of inheriting preset defaults. learningSteps: ['1m', '10m'], relearningSteps: ['10m'], enableFuzz: false, maximumInterval: 36500, clearStatsOnForget: false, }, }) type
    type Card = {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    Card
    = ReturnType<typeof
    const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
    scheduler
    .
    SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-7"; readonly config: SRSSchema<{ input: { readonly weights: readonly number[]; }; output: { readonly weights: readonly number[]; }; }>; readonly memoryState: SRSSchema<{ input: { stabilityFast: number; stability: number; difficulty: number; }; output: { stabilityFast: number; stability: number; difficulty: number; }; }>; readonly algorithm: FSRS7Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.newCard: (options?: (Omit<{
        readonly now?: Date | undefined;
    } & {
        readonly cardId?: string | number | undefined;
    }, "now"> & {
        readonly now?: Date | undefined;
    }) | undefined) => {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    newCard
    >
    type
    type PreviousCard = {
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
    }
    PreviousCard
    = Omit<
    type Card = {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    Card
    , 'stabilityFast'>
    type
    type StoredReview = {
        rating: Rating;
        review: string;
    }
    StoredReview
    = { rating:
    type Rating = 0 | 1 | 2 | 3 | 4
    Rating
    ; review: string }
    // completeHistory means all reviews since creation or the latest memory reset. // Decide this from application records, not from the number of rows alone. export function
    function migrateMemory(card: PreviousCard, logs: readonly StoredReview[], completeHistory: boolean): Card
    migrateMemory
    (
    card:
    type PreviousCard = {
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
    }
    PreviousCard
    ,
    logs: readonly
    type StoredReview = {
        rating: Rating;
        review: string;
    }
    StoredReview
    [],
    completeHistory: boolean ):
    type Card = {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    Card
    {
    if (card.state ===
    const State: Readonly<{
        readonly New: 0;
        readonly Learning: 1;
        readonly Review: 2;
        readonly Relearning: 3;
    }>
    State
    .New) {
    const { stability, stabilityFast, difficulty } =
    const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
    scheduler
    .
    SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-7"; readonly config: SRSSchema<{ input: { readonly weights: readonly number[]; }; output: { readonly weights: readonly number[]; }; }>; readonly memoryState: SRSSchema<{ input: { stabilityFast: number; stability: number; difficulty: number; }; output: { stabilityFast: number; stability: number; difficulty: number; }; }>; readonly algorithm: FSRS7Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.newCard: (options?: (Omit<{
        readonly now?: Date | undefined;
    } & {
        readonly cardId?: string | number | undefined;
    }, "now"> & {
        readonly now?: Date | undefined;
    }) | undefined) => {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    newCard
    ({
    cardId: card.cardId, }) return
    const definition: CustomScheduler<"fsrs-7", ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>
    definition
    .
    CustomScheduler<"fsrs-7", ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-7"; readonly config: SRSSchema<{ input: { readonly weights: readonly number[]; }; output: { readonly weights: readonly number[]; }; }>; readonly memoryState: SRSSchema<{ input: { stabilityFast: number; stability: number; difficulty: number; }; output: { stabilityFast: number; stability: number; difficulty: number; }; }>; readonly algorithm: FSRS7Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>.schema: SchedulerSchema<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>
    schema
    .
    SchedulerSchema<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-7"; readonly config: SRSSchema<{ input: { readonly weights: readonly number[]; }; output: { readonly weights: readonly number[]; }; }>; readonly memoryState: SRSSchema<{ input: { stabilityFast: number; stability: number; difficulty: number; }; output: { stabilityFast: number; stability: number; difficulty: number; }; }>; readonly algorithm: FSRS7Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>.card: SRSSchema<{
        input: Readonly<Omit<Readonly<{
            stabilityFast: number;
            stability: number;
            difficulty: number;
        } & {
            dueAt: Date;
            lastReviewAt: Date | null;
        } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
            readonly cardId: string | number;
            readonly reps: number;
            readonly learningStep?: number | undefined;
            readonly scheduledDays: number;
            readonly lapses: number;
        }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>;
        output: Mutable<...>;
    }>
    card
    .
    SRSSchema<{ input: Readonly<Omit<Readonly<{ stabilityFast: number; stability: number; difficulty: number; } & { dueAt: Date; lastReviewAt: Date | null; } & SchedulerCoreFields$1<"new" | "learning" | "review">> & { ...; }, keyof SchedulerCoreFields$1<...>> & SchedulerCoreFields$1<...>>; output: Mutable<...>; }>.parse(input: unknown): Mutable<Omit<Mutable<{
        stabilityFast: number;
        stability: number;
        difficulty: number;
    } & {
        dueAt: Date;
        lastReviewAt: Date | null;
    } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
        readonly cardId: string | number;
        readonly reps: number;
        readonly learningStep: number;
        readonly scheduledDays: number;
        readonly lapses: number;
    }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>
    parse
    ({
    ...card, stability, stabilityFast, difficulty, }) } if (!completeHistory) throw new Error('Keep this card on FSRS-6: incomplete history') const history = logs .filter(({ rating }) => rating !==
    const Rating: Readonly<{
        readonly Manual: 0;
        readonly Again: 1;
        readonly Hard: 2;
        readonly Good: 3;
        readonly Easy: 4;
    }>
    Rating
    .Manual)
    .map(({ rating, review }) => ({ rating, reviewTime: new Date(review), })) // replay validates dates/ratings and sorts the non-manual history. // Empty or Manual-only histories throw instead of clearing memory. const { memoryState } = new
    new Reschedule<SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>>(scheduler: SchedulerCore<...>): Reschedule<...>

    Replays a review history on top of an existing srs-kit scheduler core.

    The scheduler instance keeps the model and chronology coupled, allowing the review-time, card and memory-state types to be inferred from the selected core.

    Reschedule
    (
    const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
    scheduler
    ).
    Reschedule<SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-7"; readonly config: SRSSchema<{ input: { readonly weights: readonly number[]; }; output: { readonly weights: readonly number[]; }; }>; readonly memoryState: SRSSchema<{ input: { stabilityFast: number; stability: number; difficulty: number; }; output: { stabilityFast: number; stability: number; difficulty: number; }; }>; readonly algorithm: FSRS7Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>>.replay(input: ReplayInput<{
        stabilityFast: number;
        stability: number;
        difficulty: number;
    }, Date>, options?: RescheduleOptions): ReplayResult<{
        stabilityFast: number;
        stability: number;
        difficulty: number;
    }>

    Rebuilds model memory from the review history and returns the memory state after each review.

    replay
    ({
    ReplayInput<{ stabilityFast: number; stability: number; difficulty: number; }, Date>.history: readonly RescheduleReview<Date>[]
    history
    })
    const latestReview = history.reduce( (latest, { reviewTime }) => Math.max(latest, reviewTime.getTime()), -Infinity ) if (card.lastReviewAt?.getTime() !== latestReview) { throw new Error( 'Keep this card on FSRS-6: history does not match lastReviewAt' ) } // Only the model memory changes; dueAt, counters and learning progress survive. return
    const definition: CustomScheduler<"fsrs-7", ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>
    definition
    .
    CustomScheduler<"fsrs-7", ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-7"; readonly config: SRSSchema<{ input: { readonly weights: readonly number[]; }; output: { readonly weights: readonly number[]; }; }>; readonly memoryState: SRSSchema<{ input: { stabilityFast: number; stability: number; difficulty: number; }; output: { stabilityFast: number; stability: number; difficulty: number; }; }>; readonly algorithm: FSRS7Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>.schema: SchedulerSchema<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
        readonly name: "fsrs-7";
        readonly config: SRSSchema<{
            input: {
                readonly weights: readonly number[];
            };
            output: {
                readonly weights: readonly number[];
            };
        }>;
        readonly memoryState: SRSSchema<{
            input: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
            output: {
                stabilityFast: number;
                stability: number;
                difficulty: number;
            };
        }>;
        readonly algorithm: FSRS7Algorithm;
    }>, Chrono<...>, readonly []>, readonly [...]>>
    schema
    .
    SchedulerSchema<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-7"; readonly config: SRSSchema<{ input: { readonly weights: readonly number[]; }; output: { readonly weights: readonly number[]; }; }>; readonly memoryState: SRSSchema<{ input: { stabilityFast: number; stability: number; difficulty: number; }; output: { stabilityFast: number; stability: number; difficulty: number; }; }>; readonly algorithm: FSRS7Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>.card: SRSSchema<{
        input: Readonly<Omit<Readonly<{
            stabilityFast: number;
            stability: number;
            difficulty: number;
        } & {
            dueAt: Date;
            lastReviewAt: Date | null;
        } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
            readonly cardId: string | number;
            readonly reps: number;
            readonly learningStep?: number | undefined;
            readonly scheduledDays: number;
            readonly lapses: number;
        }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>;
        output: Mutable<...>;
    }>
    card
    .
    SRSSchema<{ input: Readonly<Omit<Readonly<{ stabilityFast: number; stability: number; difficulty: number; } & { dueAt: Date; lastReviewAt: Date | null; } & SchedulerCoreFields$1<"new" | "learning" | "review">> & { ...; }, keyof SchedulerCoreFields$1<...>> & SchedulerCoreFields$1<...>>; output: Mutable<...>; }>.parse(input: unknown): Mutable<Omit<Mutable<{
        stabilityFast: number;
        stability: number;
        difficulty: number;
    } & {
        dueAt: Date;
        lastReviewAt: Date | null;
    } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
        readonly cardId: string | number;
        readonly reps: number;
        readonly learningStep: number;
        readonly scheduledDays: number;
        readonly lapses: number;
    }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>
    parse
    ({ ...card, ...memoryState })
    } export const previousCard:
    type PreviousCard = {
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        cardId: string | number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
    }
    PreviousCard
    = {
    cardId: 'card-1', dueAt: new Date('2026-01-05T00:00:00.000Z'), lastReviewAt: new Date('2026-01-02T00:00:00.000Z'), stability: 2, difficulty: 5, state:
    const State: Readonly<{
        readonly New: 0;
        readonly Learning: 1;
        readonly Review: 2;
        readonly Relearning: 3;
    }>
    State
    .Review,
    scheduleStatus: 'review', scheduledDays: 3, learningStep: 0, reps: 3, lapses: 0, } export const storedHistory:
    type StoredReview = {
        rating: Rating;
        review: string;
    }
    StoredReview
    [] = [
    { rating:
    const Rating: Readonly<{
        readonly Manual: 0;
        readonly Again: 1;
        readonly Hard: 2;
        readonly Good: 3;
        readonly Easy: 4;
    }>
    Rating
    .Good, review: '2026-01-01T00:00:00.000Z' },
    { rating:
    const Rating: Readonly<{
        readonly Manual: 0;
        readonly Again: 1;
        readonly Hard: 2;
        readonly Good: 3;
        readonly Easy: 4;
    }>
    Rating
    .Good, review: '2026-01-01T00:10:00.000Z' },
    { rating:
    const Rating: Readonly<{
        readonly Manual: 0;
        readonly Again: 1;
        readonly Hard: 2;
        readonly Good: 3;
        readonly Easy: 4;
    }>
    Rating
    .Good, review: '2026-01-02T00:00:00.000Z' },
    ] const
    const migrated: {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    migrated
    =
    function migrateMemory(card: PreviousCard, logs: readonly StoredReview[], completeHistory: boolean): Card
    migrateMemory
    (previousCard, storedHistory, true)
    console.log( JSON.stringify( { model: 'FSRS-7', cardId:
    const migrated: {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    migrated
    .cardId,
    dueAt:
    const migrated: {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    migrated
    .dueAt,
    reps:
    const migrated: {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    migrated
    .reps,
    stabilityFast:
    const migrated: {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        learningStep: number;
        scheduledDays: number;
        lapses: number;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    }
    migrated
    .stabilityFast,
    }, null, 2 ) )
    卡片或历史情况处理方式
    新卡片(State.New),含主动重置后的卡片使用 FSRS-7 默认记忆状态,保留调度安排与统计。
    已学习卡片,具有从创建或最近一次记忆重置以来的完整历史使用 FSRS-7 权重重放,保存重建状态并保留调度安排。
    历史缺失或被截断卡片及其匹配配置继续使用 FSRS-6;不得静默清零,也不能仅凭行数宣称历史完整。
    已学习卡片的历史为空或仅有 Manual重放抛错,卡片继续使用 FSRS-6。
    日期或评分无效,或最后一次复习与 lastReviewAt 不匹配停止该卡片迁移,先核对记录。

    replay() 按时间排序有效复习并过滤 Rating.Manual,但不会解释手动遗忘或重置事件。应用必须选取最近一次记忆重置之后的完整历史,排除更早记录;仅手动调整到期时间不等于重置记忆。同一时间戳的复习应保留记录顺序。使用 dateChrono 时,时间需反序列化为有效 Date。首条保留的复习从未初始化的记忆状态开始,经过天数为零。

    示例的历史完整标志由应用判断,最后时间戳匹配并不能证明更早的复习没有缺失。迁移失败的卡片应按持久化的模型版本继续路由到 FSRS-6,不要将它们传给 FSRS-7。

    如果确实需要重新安排到期时间

    new Reschedule(scheduler).reschedule({ history, initialCard }) 会通过整套调度策略重放,返回 { card, results },可能改变到期时间、学习进度和统计。应以保留原 cardId、使用首条复习时间的 FSRS-7 新卡片作为 initialCard,不能在已有已学习卡片上再重放完整历史。生成的日志是重新计算的结果,不应替换原始历史。本文默认使用 replay(),迁移时不重新安排已有卡片的下次复习时间。

    持久化与验收

    1. 备份卡片、原始日志和配置。为每张卡片或与之可靠关联的配置保存模型版本,以及重放实际使用的权重。
    2. 增加 stabilityFast 和 v6 字段的存储,将重建记忆、模型版本及对应权重/配置引用一并提交,避免混用 FSRS-6 状态和 FSRS-7 权重。保留应用 ID 与元数据。
    3. 保持原始日志不变,并建立撤销边界:旧模型日志不得直接用于 FSRS-7 rollback()。新的 FSRS-7 日志应保存 stabilityFast 和复习前字段。
    4. 使用代表卡片验证复习、预览、撤销、同日复习、学习步骤及配置的模糊行为。仅迁移记忆时,断言到期时间、ID、学习进度和统计不变。处理失败后再切换相应卡片的模型。

    模型细节见 FSRS-7,API 组成见调度器定义、Chrono 与中间件。