Files
Hankan/types/lib/srs.d.ts
MechaCat02 e72b77d6c2 chore: take in the 16 Sep bundle — lib, curriculum v5, prompt, gate audit
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>
2026-09-16 19:49:52 +02:00

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;