The artifact was reworked after real incidents: a week of lost data, a
student taught out of order, and spelling diagnoses the model invented.
This takes the new export in verbatim; the port catches up in the
commits that follow.
Copied byte-identical from the bundle:
lib/ lexicon.js and sync.js are new; gate.js gains enforcement,
hangul.js letter-level marking, srs.js recall evidence,
conjugation.js deconjugate(); blocks.js now takes the last
block, closes gloss at "=", and parses recall, ::result and
::confirmed
data/ curriculum.json v5 — six 다지기 phase reviews; the 371
roadmap words are unchanged and no band moves
prompt/ English-only rule, recall, LETTER-LEVEL CHECK, marking
audit-gate.mjs, run-checks.sh, fixtures/ — the word gate measured
against 54 real tutor messages
CI runs run-checks.sh in place of validate.mjs alone, and `npm run check`
gains the audit. Baselines: validate PASS 0/0; audit 7 of 41 and 2 of 13.
types/lib/ declares the new API, and test/lib/ pins it: letterCheck on
the prompt's own 짧다/빫다 case, deconjugation, the roadmap-first order
that keeps 마셔 out of Phase 1, sync's three gates, and recall evidence —
including the two ways lib's evidence is looser than PORT.md, pinned as
they are so the call site that tightens them is visibly needed.
TaskHost gains a plain recall renderer so the tree typechecks against the
wider Task union.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
74 lines
2.0 KiB
TypeScript
74 lines
2.0 KiB
TypeScript
/* Declarations for lib/srs.js — the module itself ships unchanged. */
|
|
|
|
export const AGAIN: 0;
|
|
export const HARD: 1;
|
|
export const GOOD: 2;
|
|
export const EASY: 3;
|
|
export type Grade = 0 | 1 | 2 | 3;
|
|
|
|
export const NEW: 0;
|
|
export const LEARNING: 1;
|
|
export const REVIEW: 2;
|
|
export type CardState = 0 | 1 | 2;
|
|
|
|
/** Days at which a card counts as known. */
|
|
export const SECURE_INTERVAL: number;
|
|
|
|
export interface Card {
|
|
state: CardState;
|
|
interval: number;
|
|
ease: number;
|
|
/** Day number, not a timestamp — see dayNumber(). */
|
|
due: number;
|
|
reps: number;
|
|
lapses: number;
|
|
}
|
|
|
|
export function newCard(): Card;
|
|
export function grade(card: Card, g: Grade, today: number): Card;
|
|
export function markKnown(today: number): Card;
|
|
|
|
export type CardStatus = "new" | "learning" | "review" | "secure";
|
|
export function statusOf(card: Card | null | undefined): CardStatus;
|
|
|
|
/** Label for the interval a grade would produce — shown on the buttons. */
|
|
export function preview(card: Card | null | undefined, g: Grade, today: number): string;
|
|
|
|
/** Local day number, DST-safe. */
|
|
export function dayNumber(d?: Date): number;
|
|
|
|
/* ── recall evidence, kept separate from the schedule ──────────────── */
|
|
|
|
export const LEARNED_OK: number;
|
|
export const LEARNED_STREAK: number;
|
|
export const LEARNED_SPAN: number;
|
|
|
|
export interface Evidence {
|
|
ok: number;
|
|
wrong: number;
|
|
lookups: number;
|
|
streak: number;
|
|
/** Round of the first outcome of any kind. */
|
|
firstRound: number;
|
|
/** Round of the latest outcome of any kind. */
|
|
lastRound: number;
|
|
lastSeen: number;
|
|
/** Distinct rounds with an outcome. */
|
|
rounds: number;
|
|
}
|
|
|
|
export function newEvidence(): Evidence;
|
|
|
|
/** Pure: returns a new record. A lookup is never a recall and resets the streak. */
|
|
export function noteOutcome(
|
|
ev: Evidence,
|
|
outcome: "ok" | "wrong",
|
|
round: number,
|
|
lookedUp?: boolean,
|
|
): Evidence;
|
|
|
|
export function isLearned(ev: Evidence): boolean;
|
|
|
|
/** Whether a tutor's ::confirmed for this word may be stored. */
|
|
export function acceptConfirmation(ev: Evidence): boolean;
|