mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-16 03:37:13 +08:00
The overview rendered four anonymous module tiles and half a page of empty space, which undersold 63 existing lessons. It now stacks four module sections that list every lesson as a chip with status and variant dots, and the header states the real scope: 4 modules, 63 lessons, 262 variations. Mastery moves from a flat two-variation counter to per-module thresholds (3/4/4/5) backed by persisted variant signatures — a hash over each roll's expected answers. That triples the practice runs to full mastery without authoring a single new lesson, and fixes a dedup hole where the same variation counted twice after a page reload. Existing progress is preserved: `done` is sticky, so raising the bar never revokes a check mark someone already earned. Also fixes `yarn test`, which passed quoted globs Node 20 does not expand — it exited 0 without running a single test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
29 lines
810 B
TypeScript
29 lines
810 B
TypeScript
import type { Lesson, Scenario } from './types'
|
||
|
||
/**
|
||
* Identifies a rolled scenario by what the pilot actually has to say.
|
||
*
|
||
* Two rolls that demand the same answers are the same exercise, no matter how
|
||
* the rest of the scenario differs, so mastery must not count them twice.
|
||
*/
|
||
export function lessonVariantSignature(lesson: Pick<Lesson, 'fields'>, scenario: Scenario): string {
|
||
const parts = lesson.fields.map(field => {
|
||
try {
|
||
return String(field.expected(scenario) ?? '')
|
||
} catch {
|
||
return ''
|
||
}
|
||
})
|
||
|
||
return fnv1a(`${parts.length} |