fix(worksheets): validation function was converting mastery mode to manual

CRITICAL FIX: The validateWorksheetConfig() function only checked for mode === 'smart',
causing mastery mode configs to fall through to the manual mode path. This meant:
- Frontend sent mode: 'mastery' with displayRules
- Validation function created a manual mode config instead
- displayRules were lost, replaced with boolean flags
- Ten-frames didn't render because flags defaulted to false

Changes:
- validation.ts: Check for both 'smart' OR 'mastery' when using displayRules
- validation.ts: Preserve mode as 'smart' | 'mastery' instead of forcing 'smart'
- validation.ts: Include currentStepId for mastery progression tracking
- types.ts: Import and include AdditionConfigV4Mastery in WorksheetFormState type

This was the third place mastery mode needed to be handled:
1.  config-schemas.ts - Zod schema (added in previous commit)
2.  typstGenerator.ts - Problem enrichment (added in previous commit)
3.  validation.ts - Config validation (this commit)

Tests: All 14 ten-frames tests passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-11-10 10:25:43 -06:00
parent 37ed00c2b9
commit 4ad687df73
3 changed files with 13 additions and 10 deletions

View File

@ -36,7 +36,9 @@
"Bash(done)", "Bash(done)",
"mcp__sqlite__list_tables", "mcp__sqlite__list_tables",
"mcp__sqlite__describe_table", "mcp__sqlite__describe_table",
"Bash(npm test:*)" "Bash(npm test:*)",
"mcp__sqlite__read_query",
"Bash(cat:*)"
], ],
"deny": [], "deny": [],
"ask": [] "ask": []

View File

@ -4,6 +4,7 @@ import type {
AdditionConfigV4, AdditionConfigV4,
AdditionConfigV4Smart, AdditionConfigV4Smart,
AdditionConfigV4Manual, AdditionConfigV4Manual,
AdditionConfigV4Mastery,
} from '../config-schemas' } from '../config-schemas'
/** /**
@ -42,26 +43,25 @@ export type WorksheetConfig = AdditionConfigV4 & {
* Partial form state - user may be editing, fields optional * Partial form state - user may be editing, fields optional
* Based on V4 config with additional derived state * Based on V4 config with additional derived state
* *
* V4 supports two modes via discriminated union: * V4 supports three modes via discriminated union:
* - Smart mode: Has displayRules and optional difficultyProfile * - Smart mode: Has displayRules and optional difficultyProfile
* - Mastery mode: Has displayRules and optional currentStepId
* - Manual mode: Has boolean display flags and optional manualPreset * - Manual mode: Has boolean display flags and optional manualPreset
* *
* During editing, mode field may be present to indicate which mode is active. * During editing, mode field may be present to indicate which mode is active.
* If mode is absent, defaults to 'smart' mode. * If mode is absent, defaults to 'smart' mode.
* *
* This type is intentionally permissive during form editing to allow fields from * This type is intentionally permissive during form editing to allow fields from
* both modes to exist temporarily. Validation will enforce mode consistency. * all modes to exist temporarily. Validation will enforce mode consistency.
*/ */
export type WorksheetFormState = Partial<Omit<AdditionConfigV4Smart, 'version'>> & export type WorksheetFormState = Partial<Omit<AdditionConfigV4Smart, 'version'>> &
Partial<Omit<AdditionConfigV4Manual, 'version'>> & { Partial<Omit<AdditionConfigV4Manual, 'version'>> &
Partial<Omit<AdditionConfigV4Mastery, 'version'>> & {
// DERIVED state (calculated from primary state) // DERIVED state (calculated from primary state)
rows?: number rows?: number
total?: number total?: number
date?: string date?: string
seed?: number seed?: number
// Mastery progression mode
currentStepId?: string // Current step in progression path
} }
/** /**

View File

@ -138,8 +138,8 @@ export function validateWorksheetConfig(formState: WorksheetFormState): Validati
// Build mode-specific config // Build mode-specific config
let config: WorksheetConfig let config: WorksheetConfig
if (mode === 'smart') { if (mode === 'smart' || mode === 'mastery') {
// Smart mode: Use displayRules for conditional scaffolding // Smart & Mastery modes: Use displayRules for conditional scaffolding
const displayRules: DisplayRules = { const displayRules: DisplayRules = {
carryBoxes: 'whenRegrouping', carryBoxes: 'whenRegrouping',
answerBoxes: 'always', answerBoxes: 'always',
@ -154,9 +154,10 @@ export function validateWorksheetConfig(formState: WorksheetFormState): Validati
config = { config = {
version: 4, version: 4,
mode: 'smart', mode: mode as 'smart' | 'mastery', // Preserve the actual mode
displayRules, displayRules,
difficultyProfile: formState.difficultyProfile, difficultyProfile: formState.difficultyProfile,
currentStepId: formState.currentStepId, // Mastery progression tracking
...sharedFields, ...sharedFields,
} }
} else { } else {