For AI agents: the complete documentation index is available at https://open-spaced-repetition.github.io/ts-fsrs/llms.txt, the full documentation bundle is available at https://open-spaced-repetition.github.io/ts-fsrs/llms-full.txt, and this page is available as Markdown at https://open-spaced-repetition.github.io/ts-fsrs/guide/migration.md.

Migrating to v6 and FSRS-7

Package versions and model versions are separate: ts-fsrs v5 already uses FSRS-6. First move application code and stored records to the v6 API while keeping FSRS-6. Then migrate the model separately. This guide targets the v6 API in these docs; pin a v6 version that provides the documented interfaces.

Do not use legacy APIs after migration

Use defineScheduler and the explicit model entry points. Do not use fsrs(), FSRS, createEmptyCard, generatorParameters, old scheduler classes/strategies, or legacy types such as the root-exported Card, CardInput, ReviewLog and FSRSParameters in migrated code. Some remain exported for compatibility; their presence does not make them the v6 integration path. Old names below are comparison references only. The runnable examples use no legacy API or type.

For your Agent
Let an Agent complete the migration

Copy to an Agent with repository access. Confirm the migration target, then review its change TODO List. Implementation starts only after you approve the list.

1. Move to the v6 API, keeping FSRS-6

Define the scheduling policy

defineScheduler({ model, chrono }) creates a reusable definition. .use(...) adds middleware to a new definition; .create({ config }) validates configuration and creates an independent scheduler instance. Keep the definition at application scope and create instances for user or deck configuration.

A bare definition does not include all v5 scheduling policies. This example uses the same middleware order as the current standard preset: desired retention, fuzzing, statistics, scheduled days, learning steps, maximum interval, and monotonic intervals. Preserve your actual settings and FSRS-6 weights. With dateChrono, fractionalDays: false uses UTC calendar-day differences; do not change the time policy during this API-only step without checking the effect.

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 ) )

The local StoredV5Card describes application storage; it is not imported from the legacy library. Pass an existing stable database ID as cardId, and keep application-specific fields separately. The scheduler's card schema validates the converted dates and fields. Validate any additional application fields at the storage boundary as well.

Configuration mapping

v5 configurationv6 configurationMigration note
wweightsKeep the user's FSRS-6 weights for this stage; the example uses defaults only to be runnable.
request_retentiondesiredRetentionRequires the desired-retention middleware.
maximum_intervalmaximumIntervalRequires the maximum-interval middleware; the monotonic policy also uses this limit.
enable_fuzzenableFuzzRequires the fuzzing middleware; keep the old setting.
enable_short_termenableShortTermIn FSRS-6, affects both model short-term behavior and explicit learning steps.
learning_steps / relearning_stepslearningSteps / relearningStepsKeep the configured step arrays and learning progress.
Relearning step countnumRelearningStepsFor FSRS-6, set to relearningSteps.length.
forget(..., reset_count)clearStatsOnForgetNow instance configuration. v5 default: false; v6 stats middleware default: true.

Cards, logs and operations

Stored v5 fieldv6 field or handling
dueCard dueAt; deserialize to Date.
elapsed_days / log last_elapsed_daysRemoved. Compute elapsed time from timestamps with the selected chrono; do not use these old rounded values for FSRS-7 replay.
last_reviewlastReviewAt; missing/null becomes null.
scheduled_daysscheduledDays, supplied by middleware.
learning_stepslearningStep, supplied by middleware.
stability, difficulty, state, reps, lapsesPreserve during the API migration; statistics require middleware.
Application record IDcardId, reused across the card and its logs.
No corresponding fieldscheduleStatus: New → new, Learning/Relearning → learning, Review → review.
Review log reviewreviewTime, the actual review timestamp, not the card's due date.
Result { card, log }{ card, revlog }.

Derive types from your scheduler, as the example does. Card and log fields depend on the selected model, chrono and middleware. Custom v5 strategies need to be expressed through the relevant middleware hooks; renaming a strategy or subclass is not sufficient.

v5 operation (reference only)v6 operation
createEmptyCard(now)scheduler.newCard({ now, cardId })
f.next(card, now, grade)scheduler.review({ card, now, grade })
f.repeat(card, now)scheduler.preview({ card, now }) returns an iterable with an iterator provided by Symbol.iterator; use for...of to iterate. Each candidate contains { grade, card, revlog }. Select by candidate.grade rather than indexing a rating-keyed object.
f.rollback(card, log)scheduler.rollback({ card, revlog }), using the returned v6 log.
f.forget(card, now, reset_count)scheduler.forget({ card, now }); returns a card, not { card, log }. Record manual actions in your application.
f.get_retrievability(card, now, false)For a learned card with lastReviewAt, call scheduler.model.forgettingCurve(card, scheduler.chrono.difference(card.lastReviewAt, now)); the result is numeric. Handle new cards separately and format percentages in the application.

review() returns new data; persist both result.card and result.revlog. New logs preserve pre-review fields needed for rollback, including dueAt and lastReviewAt. Do not merely rename an old log's due into a v6 rollback log: old logs may lack the required pre-review snapshot. Keep historical records unchanged; convert their rating and actual review time for model replay. Cross-version undo needs a separate application snapshot or undo boundary.

Even with the same model and settings, this is not a promise of identical v5 intervals for every learning-step or fuzzing case. Check representative New, Learning, Review and Relearning cards before switching writes. DefaultScheduler is an alternative preset, but its default model is FSRS-7; explicitly choose FSRS-6 if using it during this stage.

Why the three log timestamps are not a rename

For dateChrono, the field is reviewTime, not reviewAt. Consider an overdue review: the card was last reviewed on January 1, was due on January 3, and is actually reviewed on January 4.

Meaningv5 ordinary review logv6 revlog
Previous review time: January 1due (the old implementation writes card.last_review || card.due)lastReviewAt
Original due date: January 3Not separately recorded for this learned carddueAt
Actual review time: January 4reviewreviewTime

lastReviewAt is the previous review time before the current review. Its input and output types differ:

  • DateRevlogInputFields accepts optional lastReviewAt?: Date | null. If omitted or undefined, the schema normalizes it to null; dueAt and reviewTime must still be valid Date values.
  • DateRevlogFields always contains lastReviewAt: Date | null. A normal learned-card log records the pre-review card.lastReviewAt; the first review log for a new card with no previous review contains null.
  • null does not reconstruct a missing previous review time. If an old log lacks that information, passing schema validation does not guarantee exact rollback. Do not substitute dueAt or reviewTime for it.

The card returned by the review has lastReviewAt = January 4 and a newly computed dueAt; the log holds the pre-review timestamps. Rolling back with that card and its v6 log restores January 3 as dueAt and January 1 as lastReviewAt, even when the review was early or overdue. This is why chrono separates the time used to compute elapsed days from the due date saved for undo. The runnable example above prints all three values.

Do not use a universal oldLog.due → revlog.dueAt conversion. For ordinary v5 learned-card reviews, that value normally represents the previous review. For a first review with no last_review, it instead contains the original due date; Manual/forget logs have their own semantics. A previously reset v5 New card can also carry an old last_review: the card converter normalizes State.New to lastReviewAt: null for v6.

For memory replay, only map rating and review → reviewTime. For exact cross-version undo, you need the original pre-review card snapshot (including both time fields and middleware fields), or must establish an undo boundary. Neither review nor a recomputed interval can reliably recover a due date that was never recorded, especially after early reviews, learning steps, fuzzing or manual adjustments.

2. Move from FSRS-6 to FSRS-7

Weights and state are model-specific

FSRS-6 uses 21 weights; FSRS-7 requires its own 34 weights. Use FSRS7_DEFAULT_WEIGHTS or train FSRS-7 weights. Do not append values to an FSRS-6 vector or reuse its trained weights. migrateFSRS7Parameters supplies defaults for empty input; it does not convert older parameter layouts.

FSRS-7 state has stability, stabilityFast and difficulty. Rebuild all three from history. Apply the rebuilt memoryState only to the current card. Historical revlogs are read-only input: do not modify, overwrite or backfill any of their data, including the memory states recorded at the time. Do not invent stabilityFast = 0.8 * stability for an existing learned card, or retain FSRS-6 stability/difficulty while adding a fast component. The factor used by model initialization is not a migration formula for an evolved memory state.

Use fractionalDays: true so reviews ten minutes apart retain that interval. FSRS-7 has an intrinsic fast trace: enableShortTerm: false only disables explicit learning steps when that middleware is installed; it does not disable the model's fast trace. There is no FSRS-7 model setting corresponding to FSRS-6's numRelearningSteps.

FSRS-7 default steps and learning states

For FSRS-7, DefaultScheduler uses the same learning steps ['1m', '10m'] and relearning steps ['10m'] as FSRS-3–6, and enables allowModelOverride so a longer model interval overrides the current step. Explicit settings are not overwritten by defaults. enableShortTerm still defaults to true; it controls explicit steps, not the FSRS-7 fast trace or interval-based state mapping.

With schedulerLearningStepsMiddleware registered, the final scheduled interval determines the state, even if steps are disabled, empty or completed:

Pre-review stateFinal interval below graduatingInterval (default one day)Final interval at least graduatingInterval
New / LearningLearning, scheduleStatus: learningReview, scheduleStatus: review
Review / RelearningRelearning, scheduleStatus: learningReview, scheduleStatus: review

When steps are configured, a Hard, Good, or Easy rating without an applicable step is scheduled at least graduatingInterval later, so finishing the steps, or rating a Review card Hard, Good, or Easy, will always lead to being Review. With allowModelOverride, an Again that uses the model interval always leads to Learning/Relearning, even when its interval is capped at graduatingInterval.

When no steps are configured, do not assume that no cards will be in a Learning state. only one Again can cause a card to become Relearning. Pressing Easy guarantees a card will enter a Review state. In general, Easy skips explicit steps, Good advances only when an applicable next step exists, and a zero-length step counts as no step. learningStep keeps the next step only while the card stays in Learning/Relearning; it resets to 0 when the card enters Review. It is a step index, not a review count.

These transitions belong to middleware, not FSRS7Model. A bare scheduler combining only model and chrono still returns Review, even for a sub-day interval. Update queues, state filters and statistics that rely on the old behavior.

The complete migration example in “Replay memory and preserve the schedule” explicitly preserves existing learning steps instead of relying on defaults. If the product chooses fully model-driven steps, explicitly configure learningSteps: [] and relearningSteps: []; this does not mean removing the learning-steps middleware. Verify that policy change separately from the card-field migration.

Migrate retrievability calls

Use scheduler.model.forgettingCurve(state, elapsedDays) for numeric retrievability, or scheduler.model.algorithm.curve(elapsedDays, state) to inspect both components. Both require the complete FSRS-7 state: stability, stabilityFast and difficulty, not just an FSRS-6 stability value.

Alternatively, import standalone curve from ts-fsrs/models/fsrs-7 and call curve(weights, elapsedDays, state) without constructing an algorithm instance. Supply 34 valid FSRS-7 weights. The function does not validate weights: validate stored or user-provided inputs through the appropriate schema/parameter checks first; a call to curve is not a validity test. Use the rebuilt memory state and the same FSRS-7 weights, preserving fractional elapsedDays.

Curve results include retrievability, derivative, fast, slow, fastWeight, slowWeight and total. Here total = fastWeight + slowWeight is the sum of mixture coefficients, not the total recall probability. Read retrievability when replacing an old probability call, and format percentages in the application. The algorithm instance's curve result also includes total. These APIs calculate probabilities and components; they do not migrate cards, generate logs or schedule due dates.

Replay memory and preserve the schedule

The following example is standalone. It uses a v6-shaped FSRS-6 card, maps stored log review timestamps to reviewTime, and calls Reschedule.replay() without an old-model initialState. Migration only rebuilds memory; it does not change when an existing card is next due for review (dueAt). When the user next reviews the card, FSRS-7 calculates its new due date. The ID, last review time, learning progress and counters also stay unchanged.

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 ) )
Card/history conditionAction
New card (State.New), including a deliberately reset cardInitialize FSRS-7 memory defaults; preserve its schedule and counters.
Learned card with complete history since creation or the latest memory resetReplay with FSRS-7 weights; persist the rebuilt state while preserving the schedule.
Missing or truncated historyKeep the card and its matching configuration on FSRS-6. Do not silently reset it or mark history complete based on row count alone.
Empty or Manual-only history for a learned cardReplay throws; keep the card on FSRS-6.
Invalid dates/ratings or latest review does not match lastReviewAtStop migration for that card and reconcile its records.

replay() sorts valid reviews chronologically and filters Rating.Manual. It does not interpret manual forget/reset events. The application must select the complete history after the latest memory reset, excluding earlier reviews; a manual due-date adjustment alone is not a memory reset. Preserve the recorded order of equal-time reviews. With dateChrono, timestamps must be valid Date objects after deserialization. The first retained review starts from an uninitialized memory state, with zero elapsed days.

The example's completeness flag is an application decision; matching the last timestamp does not prove that earlier reviews are present. Retain FSRS-6 scheduling for cards that fail migration, and route them by the persisted model version rather than passing them into FSRS-7.

If you intentionally want to reschedule

new Reschedule(scheduler).reschedule({ history, initialCard }) replays through the whole scheduling policy and returns { card, results }; it may change due dates, learning progress and statistics. Use a new FSRS-7 card as initialCard, with the existing cardId and the first review's time, rather than replaying full history on top of the already learned card. Its generated logs are recalculated results, not replacements for the original history. This guide defaults to replay() so migration does not reschedule existing cards.

Persist and verify the migration

  1. Back up cards, original logs and configuration. Store the model version with each card or a reliably associated configuration, including the exact weights used for replay.
  2. Add persistence for stabilityFast and the v6 fields. Commit the rebuilt memory, model version and matching weight/config reference together; do not mix FSRS-6 state and FSRS-7 weights. Preserve application IDs and metadata.
  3. Keep original logs unchanged. Establish an undo boundary: old-model logs must not be passed directly to FSRS-7 rollback(). New FSRS-7 logs must include stabilityFast and the pre-review fields.
  4. On representative cards, verify review/preview/rollback, same-day reviews, learning steps and configured fuzzing. For memory-only migration, assert that due dates, IDs, learning progress and counters are unchanged. Resolve failures before switching those cards to FSRS-7.

For the model details, see FSRS-7; for the API building blocks, see scheduler definitions, Chrono and middleware.