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)",
"mcp__sqlite__list_tables",
"mcp__sqlite__describe_table",
"Bash(npm test:*)"
"Bash(npm test:*)",
"mcp__sqlite__read_query",
"Bash(cat:*)"
],
"deny": [],
"ask": []

View File

@ -4,6 +4,7 @@ import type {
AdditionConfigV4,
AdditionConfigV4Smart,
AdditionConfigV4Manual,
AdditionConfigV4Mastery,
} from '../config-schemas'
/**
@ -42,26 +43,25 @@ export type WorksheetConfig = AdditionConfigV4 & {
* Partial form state - user may be editing, fields optional
* 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
* - Mastery mode: Has displayRules and optional currentStepId
* - Manual mode: Has boolean display flags and optional manualPreset
*
* During editing, mode field may be present to indicate which mode is active.
* If mode is absent, defaults to 'smart' mode.
*
* 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'>> &
Partial<Omit<AdditionConfigV4Manual, 'version'>> & {
Partial<Omit<AdditionConfigV4Manual, 'version'>> &
Partial<Omit<AdditionConfigV4Mastery, 'version'>> & {
// DERIVED state (calculated from primary state)
rows?: number
total?: number
date?: string
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
let config: WorksheetConfig
if (mode === 'smart') {
// Smart mode: Use displayRules for conditional scaffolding
if (mode === 'smart' || mode === 'mastery') {
// Smart & Mastery modes: Use displayRules for conditional scaffolding
const displayRules: DisplayRules = {
carryBoxes: 'whenRegrouping',
answerBoxes: 'always',
@ -154,9 +154,10 @@ export function validateWorksheetConfig(formState: WorksheetFormState): Validati
config = {
version: 4,
mode: 'smart',
mode: mode as 'smart' | 'mastery', // Preserve the actual mode
displayRules,
difficultyProfile: formState.difficultyProfile,
currentStepId: formState.currentStepId, // Mastery progression tracking
...sharedFields,
}
} else {