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>
45 lines
1.7 KiB
TypeScript
45 lines
1.7 KiB
TypeScript
/* Declarations for lib/conjugation.js — the module itself ships unchanged. */
|
|
|
|
/** Forms that do not fall out of the rules and are simply known. */
|
|
export const IRREGULAR_FORMS: Record<string, string>;
|
|
|
|
/** Dictionary form → 반말 present (해체). Returns null for non-verbs. */
|
|
export function haeche(dict: string): string | null;
|
|
|
|
/** 반말 present → 반말 past. 먹어 → 먹었어. */
|
|
export function past(present: string | null): string | null;
|
|
|
|
export function polite(present: string | null): string | null;
|
|
|
|
export type IrregularClass =
|
|
| "ㅡ" | "ㅂ" | "ㄷ" | "르" | "ㅅ" | "ㅎ" | "special" | "regular";
|
|
|
|
/** Which class a dictionary form belongs to — drives the "why" in feedback. */
|
|
export function irregularClass(dict: string): IrregularClass;
|
|
|
|
/** Human explanation of the rule applied — shown when an answer is wrong. */
|
|
export function explain(dict: string): string;
|
|
|
|
export interface SurfaceForm {
|
|
form: string;
|
|
gloss: string;
|
|
note: string;
|
|
}
|
|
|
|
/**
|
|
* Build-time: every surface form a learner will meet, mapped back to its lemma.
|
|
*/
|
|
export function surfaceForms(dict: string, gloss: string): SurfaceForm[];
|
|
|
|
/* ── reading an inflected form back to its dictionary entry ─────────── */
|
|
|
|
/** The endings the stripper tries, in the order it tries them. */
|
|
export const ENDINGS: string[];
|
|
|
|
/** Every dictionary form (…다) this surface could plausibly be. Unguarded —
|
|
pair it with a lexicon check, or 가지 (eggplant) becomes a form of 가다. */
|
|
export function deconjugateCandidates(token: string): string[];
|
|
|
|
/** The first candidate `isVerb` accepts, or null. `isVerb` is required. */
|
|
export function deconjugate(token: string, isVerb: (dictionaryForm: string) => boolean): string | null;
|