- Add nginx static server at dev.abaci.one for serving:
- Playwright HTML reports at /smoke-reports/
- Storybook (future) at /storybook/
- Coverage reports (future) at /coverage/
- NFS-backed PVC shared between artifact producers and nginx
- Smoke tests now save HTML reports with automatic cleanup (keeps 20)
- Reports accessible at dev.abaci.one/smoke-reports/latest/
Infrastructure:
- infra/terraform/dev-artifacts.tf: nginx deployment, PVC, ingress
- Updated smoke-tests.tf to mount shared PVC
- Updated smoke-test-runner.ts to generate and save HTML reports
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The testDir in playwright.config.ts is './e2e', so we should pass 'smoke'
not 'e2e/smoke' to avoid looking in ./e2e/e2e/smoke.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add AnimatedProblemTile component with MathDisplay for proper math rendering
- Add AnimatedBackgroundTiles grid component for card backgrounds
- Update FlowchartCard to accept flowchart + examples props
- Generate examples client-side for both hardcoded and database flowcharts
- Use same formatting system (formatProblemDisplay + MathDisplay) as modal
Also includes:
- Fix migration 0076 timestamp ordering issue (linkedPublishedId column)
- Add migration-timestamp-fix skill documenting common drizzle-kit issue
- Update CLAUDE.md with migration timestamp ordering guidance
- Various flowchart workshop and vision training improvements
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add dual-stream calibration: phone sends both raw and cropped preview
frames during calibration so users can see what practice will look like
- Add "Adjust" button to modify existing manual calibration without
resetting to auto-detection first
- Hide calibration quad editor overlay when not in calibration mode
- Fix rotation buttons to update cropped preview immediately
- Add rate limiting (10fps) for cropped preview frames during calibration
- Fix multiple bugs preventing dual-stream mode from working:
- Don't mark calibration as complete during preview mode
- Don't stop detection loop when receiving preview calibration
- Sync refs properly in frame mode change effects
Also includes accumulated formatting and cleanup changes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Apply code formatting across codebase
- Add new vision training boundary frames
- Update model configurations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
These files were created but never committed:
- VisionDvrControls.tsx - DVR-style playback controls
- VisionRecordingPlayer.tsx - video player component
- useSessionRecording.ts - recording data fetching hook
- cleanupVisionRecordings.ts - cleanup script
- ObserverVisionFeed.stories.tsx - storybook stories
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive skill metrics to the scoreboard that allow comparing
students across a classroom with "fun ways to compare across ability levels":
Skills Progress Section (individual view):
- Overall mastery % (weighted by BKT confidence)
- Category breakdown (basic, fiveComplements, tenComplements, etc.)
- Speed metric (normalized seconds per term) with trend arrows
- Accuracy with trend indicators
- Weekly/streak/total problem counts
Classroom Achievements Section (fair comparisons):
- Practice Warriors: most problems this week
- Streak Masters: longest practice streak
- Rising Stars: highest improvement rate (pKnown delta/week)
- Speed Champions: fastest per category (only mastered students compete)
Also includes:
- Remote camera session validation to prevent stale sessions
- Comprehensive Storybook stories for all skill metrics components
New files:
- src/lib/curriculum/skill-metrics.ts (core computation)
- src/app/api/curriculum/[playerId]/skills/metrics/route.ts
- src/app/api/classroom/[classroomId]/skills/leaderboard/route.ts
- src/hooks/useSkillMetrics.ts (React Query hooks)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The barrel export from @/lib/classroom pulls in all manager modules,
some of which have transitive dependencies on React components with
styled-system imports. Import directly from the specific manager files
(classroom-manager.ts and enrollment-manager.ts) to avoid the
dependency chain that breaks esbuild bundling for the seed script.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create classroom for current user if they don't have one
- Enroll all seeded test students in the teacher's classroom
- Enables testing of classroom leaderboard features
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add gameHistory configs to all 21 test student profiles
- Implement generateGameResults function to create scoreboard data
- Each profile has appropriate game history matching their characteristics:
- Struggling students get low scores (35-45)
- Developing students get medium scores (55-75)
- Strong students get high scores (78-95)
- Add accuracyMultiplier to TuningAdjustment interface (fixes TS error)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major changes:
- Add passive boundary capture during practice sessions via DockedVisionFeed
- Create BoundaryFrameFilters component with capture type, session, player,
and time range filtering using TimelineRangeSelector
- Add sessionId/playerId metadata to boundary frame annotations
- Update boundary-samples API to store and return session/player context
- Improve boundary detector training pipeline with marker masking
- Add preprocessing pipeline preview in training data browser
- Update model sharding (2 shards instead of 1)
Files added:
- BoundaryFrameFilters.tsx - Filter UI component
- usePassiveBoundaryCapture.ts - Hook for passive training data collection
- saveBoundarySample.ts - Shared utility for saving boundary samples
- preview-augmentation/route.ts - API for preprocessing pipeline preview
- preview-masked/route.ts - API for marker masking preview
- marker_masking.py, pipeline_preview.py - Python training utilities
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add boundary detector ML model infrastructure (MobileNetV2-based)
- Add training script for boundary detector (train_model.py)
- Add useBoundaryDetector hook for browser inference
- Add BoundaryCameraTester for real-time camera testing
- Add BoundaryImageTester for static image testing
- Add sync API support for boundary detector training data
- Add model type selector on test page (column classifier vs boundary detector)
- Add marker inpainting for training data preprocessing
- Update training wizard to support both model types
The boundary detector aims to detect abacus corners without ArUco markers,
using ML to predict corner positions from raw camera frames. Currently
requires more training data for accurate predictions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The --quantize_uint8 flag in tensorflowjs_converter corrupts model
weights, causing completely wrong predictions in the browser even
though Python testing works fine.
This was documented in .claude/CLAUDE.md but the training script
still used quantization. Model size increases (556KB → 2.2MB) but
predictions are now correct.
Removed quantization from all 3 export paths:
- SavedModel → GraphModel conversion
- Keras → LayersModel fallback
- Direct Python API fallback
After this fix, re-run training via /vision-training/train to get
a working model.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create VisionDetection.stories.tsx with interactive demos
- Add screenshot capture script for Storybook stories
- Update blog post with captured screenshots
- Include before/after comparison, progress gallery, and step demos
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix column classifier to use [0,1] normalization (model has internal
Rescaling layer that converts to [-1,1] for MobileNetV2)
- Remove quantization from model export (was corrupting weights)
- Add /vision-training/test page for direct model testing
- Add Python test script for local model verification
- Clean up verbose debug logging from classifier
- Add model tester to training results card
- Add training data hub modal and supporting components
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds hardware detection that queries TensorFlow to determine exactly
which device will be used for training:
- New Python script detect_hardware.py queries TensorFlow for available
devices (GPU/Metal/CPU)
- New API endpoint GET /api/vision-training/hardware runs the script
and caches results for 1 hour
- Training page shows hardware prominently before the "Start Training"
button with GPU/CPU badge, TensorFlow version, and system memory
On Apple Silicon Macs, shows chip type (e.g., "Apple M3 Pro GPU (Metal)")
On NVIDIA systems, shows GPU name from CUDA
Falls back to CPU with processor info if no GPU available
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements a web UI to initiate ML model training from the browser:
- Python script now outputs JSON progress with --json-progress flag
- SSE API endpoint streams training progress in real-time
- Training UI page with configuration (epochs, batch size, augmentation)
- Real-time epoch metrics display with loss/accuracy charts
- Dataset info display and training history log
- Cancel button to abort training in progress
- Auto-export to TensorFlow.js format after training
Enables training the abacus column classifier on devbox after syncing
training data from production, with visual feedback in the browser.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add /vision-training page to view collected abacus column images
- Add API routes for listing and serving training images
- Add sync-training-data.sh script to pull data from production NAS
- Remove synthetic training data generation (now using real collected data)
- Update README to document new real-data workflow
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add MIN_SECONDS_PER_PROBLEM (10s) to clamp the average time calculation
and prevent generating 100+ problems when student timing data is
anomalously low (e.g., 2-3 seconds per problem).
- Add MIN_SECONDS_PER_PROBLEM constant in session-timing.ts
- Apply Math.max() clamp in generateSessionPlan()
- Fix seed script to use realistic 30s timing instead of 5s
A 5-minute session at 10 sec/problem = 30 problems (reasonable)
A 5-minute session at 2 sec/problem = 150 problems (too many)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major refactoring of worksheet parsing to use centralized state management:
New architecture:
- WorksheetParsingContext: React context provider for parsing state
- state-machine.ts: Typed reducer with actions for streaming lifecycle
- sse-parser.ts: Shared SSE parsing utility for OpenAI Responses API
- usePartialJsonParser.ts: Progressive JSON extraction during streaming
Streaming UI improvements:
- ParsingProgressOverlay: Dark overlay on photo tile during parsing
- ParsingProgressPanel: Collapsible reasoning text panel
- ProgressiveHighlightOverlay: Problem boxes light up as LLM parses
- New streaming API routes: /parse/stream and /parse-selected/stream
Bug fixes during testing:
- Fix TypeScript error: cast event.response for id access in sse-parser
- Fix reparse reasoning display: preserve "processing" status for reparse
- Fix concurrent parsing: revert previous attachment status when switching
- Fix problem count: track dispatched problems to prevent duplicates
Components updated to use context:
- SummaryClient: Wrapped with WorksheetParsingProvider
- OfflineWorkSection: Uses context instead of local streaming state
- PhotoViewerEditor: Uses context for coordinated parsing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add cancel button to gallery thumbnails when parsing in progress
- Add cancel button to fullscreen PhotoViewerEditor when parsing
- Add cancel button for re-parsing in progress (fullscreen view)
- Track reparsingPhotoId to show correct status per-photo in both views
- Gallery shows "Re-parsing..." badge on specific photo being re-parsed
- DELETE endpoint resets parsing status for immediate retry
Also includes codebase-wide formatting from biome.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove per-problem Exclude/Restore buttons from EditableProblemRow
- Add bulk "Exclude Selected" and "Restore Selected" buttons to selection toolbar
- Add toast notifications for approve success/failure
- Close viewer and refresh page after successful approve to show updated session
- Fix mutation to properly await res.json() before returning
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix remote camera autocrop rotation by swapping ArUco corners for phone camera
(detectMarkers assumes Desk View orientation which is 180° rotated)
- Add rotate left/right buttons to CalibrationOverlay for manual calibration
- Fix mode switching bug: switching to auto mode now clears desktop calibration
on phone via new 'remote-camera:clear-calibration' socket event
- Add copy button to QR code URL with visual feedback
- Fix text selection spanning into video feed with userSelect: none
- Add flip camera and torch controls to local camera UI
- Add session persistence for remote camera reconnection
- Fix 4:3 aspect ratio for cropped abacus output
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix hook dependency issues in AbacusVisionBridge by using destructured
stable function references instead of remoteCamera object
- Add proper container dimension tracking for remote camera calibration
overlay to fix coordinate mismatch
- Add rotate180 option to perspectiveTransform to support both Desk View
(camera pointing down, needs 180° rotation) and phone cameras (no rotation)
- Phone camera cropping now uses direct mapping without rotation
The main issues fixed:
1. Hook dependencies were causing effects to run repeatedly when navigating
to remote camera URL in a different window
2. CalibrationOverlay was using hardcoded fallback dimensions instead of
actual container dimensions for remote camera
3. Perspective transform was applying 180° rotation which is wrong for
phone cameras held at normal angles
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major changes:
1. Sentinel approach for skill recency refresh
- Added 'recency-refresh' session status and SlotResult source field
- BKT skips pKnown updates for sentinel records (zero-weight)
- refreshSkillRecency() now inserts sentinel records instead of updating DB field
- Single source of truth: all lastPracticedAt comes from problem history
2. Skill progress chart (new component)
- 100% stacked area chart showing skill distribution over time
- Clickable legend cards for filtering by classification
- Adaptive time window presets (Recent, Last N, All)
- Synthetic "current" snapshot ensures chart matches legend staleness
3. Trend-aware encouragement messages
- Linear regression to detect improving/declining/stable trends
- Session timing analysis (gap detection, frequency patterns)
- Window-aware scope text ("over the past 2 weeks", "since Nov 15")
- Priority-based message selection (urgent issues first)
- Consistent "stale" terminology (not "rusty")
4. Dashboard improvements
- Virtualized session history list for performance
- Paginated session history API with cursor-based pagination
- BKT-computed lastPracticedAt used throughout (single source of truth)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixed the seed script to reliably produce "developing" skill classifications
(pKnown 0.5-0.8) by correcting several issues:
- Fix BKT simulation to only apply learning transition after CORRECT answers
(matching actual updateOnCorrect vs updateOnIncorrect behavior)
- Remove result shuffling to preserve designed correct/incorrect sequence order
- Force single-skill problem annotations to avoid multi-skill blame distribution
- Add multiple pattern generators for finding developing-range sequences
The simulation now accurately predicts actual BKT outcomes, enabling 10
developing classifications across 6 test profiles.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add simulateLegacyData option to SkillConfig interface
- When set, generateSlotResults omits helpLevelUsed field to simulate legacy data
- Update NaN Stress Test profile to test 3 skills with legacy data format
- This tests the actual production issue where old sessions lack helpLevelUsed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All 15 profiles now have correct category assignments:
- 5 BKT profiles (category: 'bkt')
- 4 Session profiles (category: 'session')
- 6 Edge case profiles (category: 'edge')
This enables CLI filtering when seeding specific profile types.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, skill stats (attempts, correct, accuracy) were stored as
persisted aggregates in playerSkillMastery and updated incrementally.
This caused issues with seeded test data showing "0 correct".
Now:
- analyzeSkillPerformance() computes stats from session results on-the-fly
- findStrugglingSkills() computes accuracy from session results
- Seeder no longer needs to update aggregate columns
Benefits:
- Single source of truth (session results)
- No drift between aggregates and actual data
- Seeded data automatically works correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename "⚖️ Balanced Mix" → "⚖️ Multi-Weak Remediation" to match actual output
- Update intention notes to reflect BKT's natural tendency to push skills to extremes
- Remove tuning criteria that fought against realistic behavior
- Focus profiles on app feature coverage rather than perfect BKT states
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major changes:
- Merge SessionSummary and SessionOverview into unified experience
- Add "Problems Worth Attention" section with expandable problem details
- Add "All Problems" collapsible section with compact/detailed toggle
- Keep auto-pause timing info in unified view
- Remove debug view toggle from SummaryClient
- Delete SessionOverview.tsx (replaced by new components)
New components:
- AllProblemsSection.tsx - collapsible all-problems view
- ProblemToReview.tsx - expandable problem row with reason badges
- sessionSummaryUtils.ts - filtering utilities for attention-worthy problems
Bug fix:
- Fix ROTATION_MULTIPLIERS import in DashboardClient (was undefined due to re-export chain)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit includes accumulated work from the SessionMode system:
- Add SkillUnlockBanner component for celebrating skill mastery
- Improve SessionSummary to show skill unlock celebrations
- Add session detail page at /practice/[studentId]/session/[sessionId]
- Update seedTestStudents script with more realistic test data
- Extend skill-tutorial-config with more skill mappings
- Improve BKT compute with better uncertainty handling
- Update progress-manager with skill completion tracking
- Remove legacy sessions API routes (replaced by session-plans)
- Add migration 0037 for practice_sessions schema cleanup
- Add plan documents for celebration wind-down and SessionMode
- Update gitignore to exclude db backups
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Student Notes Feature:
- Add notes column to players table with migration
- Create NotesModal component with zoom animation from student tile
- Add notes button on each student card in StudentSelector
- Support viewing and editing notes directly in modal
- Fix modal reopening bug with pointerEvents during animation
- Fix spring animation to start from clicked tile position
BKT & Curriculum Improvements:
- Add configurable BKT thresholds via admin settings
- Add skill anomaly detection API endpoint
- Add next-skill recommendation API endpoint
- Add problem history API endpoint
- Improve skills page with BKT classifications display
- Add skill tutorial integration infrastructure
Dashboard & Session Improvements:
- Enhanced dashboard with notes tab
- Improved session summary display
- Add StartPracticeModal stories
Test Infrastructure:
- Add seedTestStudents.ts script for BKT manual testing
- Add generateTrajectoryData.ts for simulation data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove the sd-sub-borrow skill as it was redundant with the existing
"Two-digit with ones place borrowing" skill which naturally covers
problems like 52-17, 43-18, etc.
The skill was problematic because:
- digitRange: { min: 1, max: 1 } constrained both operands to single digits
- But the description "13-7, 15-8" implied 2-digit minus 1-digit
- This contradiction made it impossible to generate appropriate problems
- Students were seeing either 0% or 100% of the intended pattern
Rather than fix the complex asymmetric digit range logic, we're removing
the skill entirely. The progression now flows:
- sd-sub-no-borrow (single-digit without borrowing)
- td-sub-no-borrow (two-digit without borrowing)
- td-sub-ones-borrow (two-digit with ones place borrowing)
This provides a cleaner, more natural progression.
Changes:
- Remove sd-sub-borrow skill definition from skills.ts
- Remove 'sd-sub-borrow' from SkillId type union
- Update td-sub-no-borrow prerequisites to reference sd-sub-no-borrow
- Remove sd-sub-borrow from skillMigration.ts mapping
- Remove generateTeensMinusSingles() function from problemGenerator.ts
- Revert generateOnesOnlyBorrow() to standard logic
Also includes previous fixes:
- Fix AllSkillsModal tab button types to prevent modal closing
- Add operator-specific display rules for mixed mode
- Add borrowNotation and borrowingHints to displayRules schema
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed two critical bugs preventing ten-frames from rendering:
1. **Mastery mode not handled** (typstGenerator.ts:61)
- Code only checked for 'smart' | 'manual' modes
- Mastery mode fell into manual path, tried to use boolean flags that don't exist
- Resulted in all display options being `undefined`
- Fix: Check for both 'smart' OR 'mastery' modes (both use displayRules)
2. **Typst array membership syntax** (already fixed in previous commit)
- Used `(i in array)` which doesn't work in Typst
- Changed to `array.contains(i)`
Added comprehensive unit tests (tenFrames.test.ts):
- Problem analysis tests (regrouping detection)
- Display rule evaluation tests
- Full Typst template generation tests
- Mastery mode specific tests
- All 14 tests now passing
Added debug logging to trace display rules resolution:
- displayRules.ts: Shows rule evaluation per problem
- typstGenerator.ts: Shows enriched problems and Typst data
- Helps diagnose future issues
The issue was that mastery mode (which uses displayRules like smart mode)
was being treated as manual mode (which uses boolean flags), resulting in
undefined display options.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement complete worksheet grading system with AI analysis and mastery tracking:
Features:
- GPT-5 vision integration for single-pass grading (OCR + analysis)
- Three upload modes: file upload, desktop camera, QR code for smartphone
- Real-time batch upload workflow via QR code scanning
- Automatic mastery profile updates based on grading results
- AI feedback with error pattern detection and next step suggestions
- Guest user support for anonymous uploads
Technical Implementation:
- New database tables: worksheet_attempts, problem_attempts, worksheet_mastery
- Removed foreign key constraints to support guest users
- Session-based batch uploads for efficient multi-worksheet grading
- Validation and retry logic for robust AI responses
- Browser-compatible UUID generation (Web Crypto API)
Components:
- CameraCapture: Desktop/mobile camera capture with high resolution
- QRCodeDisplay: Real-time upload tracking with 2-second polling
- UploadWorksheetModal: Unified interface with three upload tabs
- AttemptResultsPage: Detailed grading results with AI analysis
API Endpoints:
- POST /api/worksheets/upload: Upload and trigger grading
- GET /api/worksheets/sessions/[sessionId]: Poll batch uploads
- GET /api/worksheets/attempts/[attemptId]: Get grading results
Cost: ~$0.04 per worksheet graded
Documentation:
- AI_MASTERY_ASSESSMENT_PLAN.md: Complete system architecture
- PROMPTING_STRATEGY.md: GPT-5 prompting and validation
- UX_EXECUTIVE_SUMMARY.md: Stakeholder-friendly overview
- UX_UI_PLAN.md: Complete interface design
- IMPLEMENTATION_STATUS.md: Testing checklist
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Recover all changes from stash including:
- Linter/formatter updates across codebase
- Settings permission updates for git checkout
This commit captures the complete state of work that was
stashed during the previous session's git operations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Created config-panel/ subdirectory and extracted reusable UI components
from the monolithic 2550-line ConfigPanel.tsx file.
Extracted components:
- utils.tsx: getScaffoldingSummary() function
- SubOption.tsx: Nested toggle UI component
- ToggleOption.tsx: Main toggle option with description
Changes:
- Created src/app/create/worksheets/addition/components/config-panel/ directory
- Moved 3 helper functions/components to separate files (~240 lines)
- Updated ConfigPanel.tsx to import from new locations
- Removed unused imports (Checkbox, findNearestPreset)
- File size reduced: 2550 → 2306 lines (-244 lines)
Zero functionality change - all components work identically.
Part 1 of 5-phase refactoring plan.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Two critical issues fixed:
1. **Duplicate numerals**: Both AbacusSVGRenderer and AbacusReact were rendering
numerals when showNumbers={true}, causing two overlapping number displays.
- Disabled SVG text numerals in AbacusSVGRenderer (line 436: added `false &&`)
- NumberFlow provides better animated numerals, keep only those
2. **White numerals in dark mode**: NumberFlow components were inheriting CSS
color from parent, turning white in dark mode (unreadable on light frames).
- Added explicit color style to NumberFlow: uses themeAwareCustomStyles
- Now consistently dark (rgba(0,0,0,0.8)) regardless of page theme
This was the root cause of the "white numerals everywhere" issue - the
NumberFlow components were inheriting dark mode CSS colors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updates typstGenerator.ts to handle both addition and subtraction:
- Import WorksheetProblem union type instead of just AdditionProblem
- Import subtraction rendering and analysis functions
- Update calculateMaxDigits to handle both operators
- Update problem enrichment to analyze addition vs subtraction
- Generate Typst problem data with operator discriminator
- Dispatch to correct rendering function based on operator
- Update displayRules to handle both ProblemMeta and SubtractionProblemMeta
Also updates:
- problemGenerator.ts: Add operator field to AdditionProblem
- displayRules.ts: Support AnyProblemMeta union type
- validation.ts: Add operator to shared config fields
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove all scaffolding (carry boxes, answer boxes, place value colors) from ten-frame examples
- Show only the core addition problems with ten-frame visualization
- Add transparent background support for blog examples
- Implement smart color replacement for dark theme visibility:
- White operator symbols (+) and horizontal bars (visible on dark background)
- Black digits on white cells (preserved contrast)
- White structural borders and lines
- Update generateTenFrameExamples.ts with post-processing to handle SVG colors
- Regenerate all 4 ten-frame example SVGs with clean, minimal presentation
The examples now focus purely on demonstrating the ten-frame concept
without distracting extra scaffolding elements.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes production error "Cannot read properties of undefined (reading 'carryBoxes')"
that occurred when users tried to adjust difficulty settings.
Root cause: displayRules was undefined for new users or users with old V1 config
in database. Difficulty adjustment buttons accessed displayRules.carryBoxes without
checking if displayRules existed first.
Changes:
- AdditionWorksheetClient: Initialize displayRules with defaults when missing
- ConfigPanel: Use null-coalescing operators instead of non-null assertions
- ConfigPanel: Add error logging when required fields are missing
- NEW: WorksheetErrorBoundary component to catch all errors in worksheet page
- page.tsx: Wrap client component with error boundary
This ensures users see helpful error messages instead of blank pages,
and never need to open the browser console to understand what went wrong.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix script to use correct displayRules property access
- Use valid rule modes (whenRegrouping, when3PlusDigits, whenMultipleRegroups)
- Generate 4 examples with same problem complexity but different scaffolding
- Add 'as const' assertions for TypeScript literal type inference
Generated SVGs:
- full-scaffolding.svg
- medium-scaffolding.svg
- minimal-scaffolding.svg
- no-scaffolding.svg
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add debugging script to visualize the constrained 2D difficulty progression:
- Traces 30 steps from beginner → maximum difficulty
- Shows path through (regrouping, scaffolding) space as 2D ASCII grid
- Marks preset positions (BEG, EAR, INT, ADV, EXP)
- Visualizes constraint band boundaries
- Helps verify navigation completeness and detect cycles
Usage: npx tsx scripts/traceDifficultyPath.ts
Output shows diagonal progression through pedagogical constraint band,
confirming no dead ends or invalid states.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>