fix(worksheets): add mastery mode to Zod schema validation

CRITICAL FIX: Config validation was failing with "No matching discriminator"
error because the Zod schema only recognized 'smart' and 'manual' modes,
not 'mastery'.

When validation failed, it fell back to default config, losing the displayRules
configuration and causing showTenFrames to be false even when it should be true.

Changes:
- Added `additionConfigV4MasterySchema` with displayRules (like smart mode)
- Added 'mastery' to the discriminated union
- Exported `AdditionConfigV4Mastery` type
- Mastery mode includes optional `currentStepId` for progression tracking

This fixes the validation error:
```
Failed to parse addition config, using defaults: ZodError: [
  {
    "code": "invalid_union",
    "note": "No matching discriminator",
    "discriminator": "mode"
  }
]
```

Now config validation will pass and displayRules will be preserved.

🤖 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:08:28 -06:00
parent b36df3a40c
commit 003f1d11cc
1 changed files with 70 additions and 0 deletions

View File

@ -336,15 +336,85 @@ const additionConfigV4ManualSchema = additionConfigV4BaseSchema.extend({
manualPreset: z.string().optional(),
})
// Mastery Progression Mode for V4
const additionConfigV4MasterySchema = additionConfigV4BaseSchema.extend({
mode: z.literal('mastery'),
// Mastery mode uses displayRules like smart mode (conditional scaffolding)
displayRules: z.object({
carryBoxes: z.enum([
'always',
'never',
'whenRegrouping',
'whenMultipleRegroups',
'when3PlusDigits',
]),
answerBoxes: z.enum([
'always',
'never',
'whenRegrouping',
'whenMultipleRegroups',
'when3PlusDigits',
]),
placeValueColors: z.enum([
'always',
'never',
'whenRegrouping',
'whenMultipleRegroups',
'when3PlusDigits',
]),
tenFrames: z.enum([
'always',
'never',
'whenRegrouping',
'whenMultipleRegroups',
'when3PlusDigits',
]),
problemNumbers: z.enum([
'always',
'never',
'whenRegrouping',
'whenMultipleRegroups',
'when3PlusDigits',
]),
cellBorders: z.enum([
'always',
'never',
'whenRegrouping',
'whenMultipleRegroups',
'when3PlusDigits',
]),
borrowNotation: z.enum([
'always',
'never',
'whenRegrouping',
'whenMultipleRegroups',
'when3PlusDigits',
]),
borrowingHints: z.enum([
'always',
'never',
'whenRegrouping',
'whenMultipleRegroups',
'when3PlusDigits',
]),
}),
// Optional: Current step in mastery progression path
currentStepId: z.string().optional(),
})
// V4 uses discriminated union on 'mode'
export const additionConfigV4Schema = z.discriminatedUnion('mode', [
additionConfigV4SmartSchema,
additionConfigV4ManualSchema,
additionConfigV4MasterySchema,
])
export type AdditionConfigV4 = z.infer<typeof additionConfigV4Schema>
export type AdditionConfigV4Smart = z.infer<typeof additionConfigV4SmartSchema>
export type AdditionConfigV4Manual = z.infer<typeof additionConfigV4ManualSchema>
export type AdditionConfigV4Mastery = z.infer<typeof additionConfigV4MasterySchema>
/** Union of all addition config versions (add new versions here) */
export const additionConfigSchema = z.discriminatedUnion('version', [