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>
57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
/* Declarations for lib/sync.js — the module itself ships unchanged.
|
|
|
|
lib/sync.js syncs four whole documents. The port syncs rows (PORT.md), so
|
|
it applies the same three gates — hydration, a counter rather than a
|
|
clock, no silent shrinking — row by row rather than calling this module.
|
|
It is declared here so its behaviour stays pinned by tests. */
|
|
|
|
export const DOCS: ("srs" | "log" | "meta" | "chat")[];
|
|
|
|
/** How much a copy holds. Shrinking is always deliberate, never a race. */
|
|
export function weigh(name: string, d: unknown): number;
|
|
|
|
/** A document as it travels: stamp, counter, data, deliberate-shrink flag. */
|
|
export interface RemoteDoc<T = unknown> {
|
|
u?: number;
|
|
v?: number;
|
|
d?: T;
|
|
x?: 1;
|
|
}
|
|
|
|
export interface LocalDoc<T = unknown> {
|
|
version?: number;
|
|
stamp?: number;
|
|
data?: T;
|
|
}
|
|
|
|
/** Is the copy that just arrived later than ours? */
|
|
export function isLater(remote: RemoteDoc, localVersion: number, localStamp: number): boolean;
|
|
|
|
export function reconcile(
|
|
name: string,
|
|
remote: RemoteDoc | null | undefined,
|
|
local: LocalDoc,
|
|
): "ignore" | "adopt" | "reassert";
|
|
|
|
export interface WriterDocState {
|
|
version: number;
|
|
stamp: number;
|
|
dirty: boolean;
|
|
hydrated: boolean;
|
|
intent: boolean;
|
|
}
|
|
|
|
export interface Writer<R> {
|
|
state: Record<string, WriterDocState>;
|
|
touch(name: string, deliberateShrink?: boolean): WriterDocState;
|
|
hydrate(name: string): WriterDocState;
|
|
adopted(name: string, remote: RemoteDoc): WriterDocState;
|
|
reasserted(name: string, remote: RemoteDoc): WriterDocState;
|
|
flush(name: string, data: unknown): R | null;
|
|
}
|
|
|
|
export function makeWriter<R>(opts: {
|
|
push: (name: string, body: RemoteDoc) => R;
|
|
now?: () => number;
|
|
}): Writer<R>;
|