- Add classroom data (enrolled, current presence) to useStudentActions hook
- Add enterSpecificClassroom handler for entering a specific classroom
- Replace simple enter/leave actions with smart classroom section:
- In classroom: shows presence indicator with leave option
- 1 enrollment: direct enter action
- Multiple enrollments: Radix submenu with classroom list
- Always shows enroll option
- Remove EnterClassroomButton from dashboard (now handled by StudentActionMenu)
- Fix EnrollChildModal z-index to use same value as overlay
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add StudentActionMenu to student dashboard with inline variant
- Build proper StudentActionData with relationship/activity info
- Use useEnrolledClassrooms and useMyClassroom hooks for context
- Fix z-index layering for sub-modals (FamilyCodeDisplay, EnrollChildModal, SessionObserverModal)
- Use Z_INDEX.TOOLTIP (15000) for nested modals to appear above parent modals
- Remove unnecessary portal from FamilyCodeDisplay
- Add variant prop to StudentActionMenu: 'card' (absolute) vs 'inline' (normal flow)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Dynamic import echarts-for-react in SkillProgressChart, ValidationCharts,
and SkillDifficultyCharts to avoid bundling 58MB echarts library
- Lazy load game-registry in CreateRoomModal to prevent all arcade games
from being bundled into every page using PageWithNav
The practice page was bundling echarts (58MB) and all arcade game code
because of static imports in shared components. These changes ensure:
- echarts only loads when charts are actually rendered
- game-registry only loads when CreateRoomModal is opened
Bundle size: 47MB → 115KB (99.8% reduction)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create MiniStartPracticeBanner component showing session mode or active session status
- Shows "Start" for idle students (navigates to dashboard with startPractice=true)
- Shows "Resume" for practicing students (parent view)
- Shows "Watch" for practicing students (teacher view, opens SessionObserverModal)
- Add session observer integration for teachers to watch active sessions
- Mode-specific styling: amber for remediation, green for progression, blue for maintenance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add PageTransitionContext to manage transition state across navigation
- Add PageTransitionOverlay component with react-spring animations
- Add fullscreen ⛶ button to NotesModal header
- Implement cross-fade transitions:
- Modal fades out while overlay fades in at modal position
- Overlay expands to fullscreen during navigation
- Overlay fades out while dashboard content fades in
- Use sessionStorage to persist transition state across page navigation
- Add pulse keyframe animation for loading indicator
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Completes Steps 14-18 of the unified student list plan:
Step 14: Move edit mode to secondary menu
- Replace prominent Edit button with ⋮ dropdown menu
- Add "Select Multiple" option, "Done" button in edit mode
Step 15-16: Clean up deprecated components
- Remove ClassroomDashboard, ClassroomTab, StudentManagerTab exports
- Add StudentQuickLook alias for NotesModal
Step 17: Real-time updates
- Add useClassroomSocket to PracticeClient for live updates
- Teachers now see presence/session changes in real-time
Step 18: Mobile responsive polish
- ViewSelector: horizontal scroll on mobile, wrap on desktop
- NotesModal: responsive height for virtual keyboard
Bonus: Arrow key navigation in QuickLook modal
- Left/Right/Up/Down arrows navigate between students
- Uses bounding rects to find nearest card in direction
- Disabled when editing notes (textarea focused)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract all student action logic into a single useStudentActions hook
used by both StudentActionMenu (on tiles) and NotesModal (in quicklook).
This ensures consistent action availability across the UI.
Key changes:
- Create useStudentActions hook with actions, handlers, and modal state
- Create StudentActionMenu as thin component using the hook
- Refactor NotesModal to use same hook (removes duplicated logic)
- Add studentActions.ts for shared types and getAvailableActions
- Clean up actionContext prop drilling from StudentSelector/PracticeClient
- Add useUnifiedStudents hook for consistent student data across views
- Add ViewSelector component for grid/list toggle
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This rule documents the failure pattern from December 2025 where
columns were added directly to the local dev database, causing
migration 0043 to be committed as a no-op. Production never got
the columns and crashed.
The rule requires all schema changes to go through the Drizzle
migration system.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The is_paused column was missing from migration 0043, causing a production
error: "SqliteError: no such column 'is_paused'"
The other pause columns (paused_at, paused_by, paused_reason) were added
manually during development but is_paused was overlooked.
This commit:
- Reverts 0043 to a no-op (those columns already exist)
- Adds 0044 to add only the missing is_paused column
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Teacher observing a student's practice session can now:
- Dock their MyAbacus alongside the observed problem (AbacusDock pattern)
- Manipulate their abacus to sync the student's docked abacus
- See their abacus sync when the student manipulates theirs
Key changes:
- SessionObserverModal: Uses same AbacusDock pattern as ActiveSession
with ResizeObserver for height matching
- MyAbacus: Fixed docked mode to use setDockedValue instead of
setAbacusValue, ensuring read/write use same state source
- MyAbacusContext: Added contextAbacusValue for external abacus control
- useSessionObserver: Sends abacus-control events to student
- useSessionBroadcast: Receives abacus-control events from teacher
The two-way sync flow:
1. Teacher→Student: Teacher moves beads → sendControl(set-abacus-value)
→ student's abacus syncs via onAbacusControl callback
2. Student→Teacher: Student moves beads → broadcasts studentAnswer
→ observer receives → setDockedValue syncs teacher's abacus
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Auto-transition: When teacher observes a tutorial that completes,
automatically switch to observing the student's practice session
- Added polling mechanism while waiting for session to start
- Shows "Waiting for practice to start" overlay with cancel button
- 30-second timeout to prevent indefinite waiting
- Fixed NaN display in complexity tooltip "Per term (avg)":
- Added !Number.isNaN() checks in PurposeBadge and ActiveSession
- Fixed problemGenerator reduce to explicitly filter NaN values
(the ?? operator only catches null/undefined, not NaN)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Teachers can now observe students' skill tutorials in real-time:
- Added TutorialObserverModal that reuses SkillTutorialLauncher component
- Student broadcasts tutorial state via WebSocket (useSkillTutorialBroadcast)
- Teacher receives live updates via useClassroomTutorialStates
- Teacher controls work: Start, Skip, Prev, Next, Complete buttons
- Socket server forwards skill-tutorial-state and skill-tutorial-control events
- Added onControl prop to SkillTutorialLauncher and TutorialPlayer
- In observation mode, buttons send control events instead of changing local state
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add onBroadcastStateChange callback to ActiveSession for real-time state
- Change studentAnswer from number to string for digit-by-digit display
- Map internal phases correctly: inputting→problem, showingFeedback→feedback, helpMode→tutorial
- Update SessionObserverModal to display string answers directly
- Teachers can now see each digit as students type their answers
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Teachers can now observe students' practice sessions in real-time:
- Added SessionObserverModal with live problem display
- Created useSessionObserver hook for receiving broadcasts
- Refactored useSessionBroadcast to re-broadcast on observer join
- Added join-session socket event for session channel subscription
- Created shared PurposeBadge component with tooltip
- Created shared PracticeFeedback component
- Fixed tooltip z-index to work inside modals (15000)
- Used Z_INDEX constants throughout modal components
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Step 1: Student broadcasts practice state via WebSocket
- Create useSessionBroadcast hook that emits practice-state events
- Only broadcasts when student is present in a classroom
- Wired into PracticeClient to broadcast during active sessions
Step 2: Teacher sees active sessions indicator
- Add useActiveSessionsInClassroom to ClassroomTab
- Show "Practicing" badge with problem progress for active students
- Blue styling for practicing students vs green for idle
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Provides API for useActiveSessionsInClassroom hook to fetch
which students in a classroom are currently practicing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix parent enrollment creation cache invalidation (Step 7)
- Add usePlayerEnrollmentSocket for student-side enrollment updates (Step 8)
- Update parent approval route to use socket-emitter helper (Step 8)
- Fix enter/leave classroom to use centralized playerKeys (Step 9)
- Add session started/ended socket events for active sessions (Step 11)
- Teacher sees real-time session updates when students in classroom
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add studentUnenrolled event to socket system for real-time updates
- Emit socket events when teacher or parent unenrolls a student
- Handle enrollment-approved events in usePlayerPresenceSocket
- Add EnrollChildModal with reactive success state and auto-close
- Detects when teacher approves while modal is open
- Shows countdown progress bar in Done button
- Smooth fade-out transition on close
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Contextual Enrollment Flow:
- Add "Enroll in Classroom" option to EnterClassroomButton dropdown
- Add "Enroll" button to NotesModal for child-specific enrollment
- Remove global enrollment button from PracticeClient
- Show EnterClassroomButton even without enrollments
Reactivity Improvements (Steps 0-6):
- Create query invalidation map for consistent cache updates
- Create type-safe socket emission helper
- Add EnrollmentRequestApprovedEvent and EnrollmentRequestDeniedEvent types
- Teacher approval/denial now emits socket events to parents
- Parent denial now emits socket events to classroom (teacher)
- Refactor useParentSocket and useClassroomSocket to use invalidateForEvent
- Add enrollment-request-approved and enrollment-request-denied listeners
Both teacher and parent dashboards now update in real-time without reloading.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add socket events when parent approves enrollment request
- Emits enrollment-request-approved and enrollment-approved to classroom channel
- Teacher's view updates immediately without page reload
- Add socket events to notify parents of new enrollment requests
- Teacher adding student by family code now emits to parent's user channel
- Parent sees new pending approvals in real-time
- Create useParentSocket hook for parent real-time notifications
- Connects to user:${userId} channel
- Listens for enrollment-request-created events
- Invalidates pendingParentApprovals query
- Add "Awaiting Parent Approval" section in StudentManagerTab
- Shows teacher-initiated requests waiting for parent response
- Styled in blue to differentiate from pending requests
- Add useAwaitingParentApproval hook and query key
- Add AddStudentByFamilyCodeModal for teachers to add students
- Auto-approve requester's side when creating enrollment requests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add EnrollChildFlow component for parents to enroll children
- Add enrollment hooks (useEnrolledStudents, useCreateEnrollmentRequest, etc.)
- Update StudentManagerTab with enrolled students and pending requests
- Add "Enroll in another classroom" option for teachers who are parents
- Fix critical auth bug: convert guestId to user.id in all classroom API routes
The API routes were incorrectly using viewerId (guestId from cookie) when
they should have been using users.id. This caused 403 errors for all
classroom operations. Fixed by adding getOrCreateUser() to convert
guestId to proper user.id before calling business logic functions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The classroom system migration files (0041_classroom-system.sql and
0042_classroom-system-indexes.sql) were created manually without using
drizzle-kit generate, so they weren't registered in _journal.json.
This caused drizzle to skip these migrations, resulting in:
- No parent_child table
- No family_code column on players
- No classrooms/enrollments tables
Fixes production error on /practice page.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add teacher classroom functionality allowing users to create a classroom
and manage students:
- Add classroom query keys for React Query cache management
- Create useClassroom hooks (useMyClassroom, useClassroomByCode,
useCreateClassroom, useIsTeacher)
- Add classroom UI components:
- ClassroomCodeShare: Display join code with copy button
- CreateClassroomForm: Form to create a classroom
- ClassroomTab: Live classroom view (empty state for Phase 6)
- StudentManagerTab: Enrolled students list (empty state for Phase 4)
- ClassroomDashboard: Main teacher dashboard with tabs
- Integrate into PracticeClient with conditional routing:
- Teachers see ClassroomDashboard with own children shown separately
- Parents see normal student list with "Become a Teacher" option
- Fix API route to remove non-existent 'image' field from User type
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add family code system allowing multiple parents to access the same child's
practice data. This is the foundation for the Suzuki Triangle model where
both parents can supervise daily practice.
Key features:
- Family codes (FAM-XXXXXX) per student for sharing access
- FamilyCodeDisplay modal for viewing/copying/regenerating codes
- LinkChildForm modal for linking to existing child via code
- parent_child junction table for many-to-many relationships
- React Query mutations with proper cache invalidation
API routes:
- GET/POST /api/family/children/[playerId]/code - manage family codes
- POST /api/family/link - link to child via family code
- GET /api/family/children - list linked children
Also includes classroom system foundation (Phase 1):
- Classroom, enrollment, and presence schemas
- Teacher classroom management APIs
- Student enrollment request workflow
- Real-time presence tracking infrastructure
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ExtendedSkillClassification type with 5 categories (strong, stale, developing, weak, unassessed)
- Add getExtendedClassification() as single source of truth for classification
- Add SkillDistribution interface for consistent counts across components
- Update ProgressDashboard to display grouped skill categories with visual hierarchy
- Update DashboardClient to compute full 5-category distribution
- Update SkillProgressChart to use shared types from BktContext
This ensures Overview and Skills tabs use identical classification logic.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Tooltip now shows MASTERED, IN PROGRESS, NOT STARTED group headers
- Categories organized under their respective groups (Strong/Stale, Developing/Weak, Unassessed)
- Styled tooltip background for light/dark mode
- Skip empty categories (0 count) from tooltip display
- Consistent visual hierarchy with legend cards
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add diagonal stripe pattern to Stale and Weak categories to indicate "needs attention"
- Update color scheme: Strong/Stale share green family, Developing stays blue, Weak is coral
- Make Unassessed nearly transparent with dashed border in legend
- Legend cards now have colored backgrounds matching chart colors
- Add group headers (Mastered, In Progress, Not Started) with vertical dividers
- Ensure text contrast works in both light and dark modes
- Add "(7+ days ago)" descriptor to Stale card for clarity
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add "Needs Attention" section to /practice page surfacing struggling students
- Implement intervention detection (struggling, declining, stale, absent, plateau)
- Group skill chart legend into Mastered/In Progress/Not Started hierarchy
- Use color families: green for mastered (strong+stale), patterns for attention states
- Add diagonal stripe pattern to Stale and Weak categories in chart and legend
- Update tooltip to show same grouped structure with tree branches
- Fix encouragement message to not celebrate when weak skills are growing
- Make Unassessed transparent/dashed to fade into background
🤖 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>
Complete removal of per-skill accuracy tracking from the practice system.
BKT-based mastery classification (weak/developing/strong) now serves as
the sole measure of skill proficiency.
Changes:
- Remove accuracy field from skill stats and related components
- Remove accuracyMultiplier from tuning adjustments
- Simplify session summary to use BKT classification only
- Update DashboardClient to remove accuracy-based displays
- Clean up unused accuracy utility functions and theme colors
- Update journey simulator to remove accuracy references
This aligns with the design principle that BKT pKnown is a more reliable
indicator of true mastery than raw accuracy percentages.
🤖 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>
The codebase previously used "help level" terminology (HelpLevel type,
helpLevelUsed field, helpLevelWeight function) which implied a graduated
scale. Since the system now only tracks whether help was used or not,
this renames everything to use proper boolean terminology.
Changes:
- Delete HelpLevel type, use boolean directly
- Rename helpLevelUsed → hadHelp in SlotResult
- Rename lastHelpLevel → lastHadHelp in PlayerSkillMastery schema
- Rename helpLevelWeight() → helpWeight() with boolean parameter
- Update all components, tests, stories, and documentation
- Add database migration for column rename
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Auto-generated fresh SVG examples and unified gallery from latest templates.
Includes comprehensive crop mark demonstrations with before/after comparisons.
Files updated:
- packages/templates/gallery-unified.html
🤖 Generated with GitHub Actions
Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.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>
Root cause: Old production data (before Dec 2024) is missing the
`helpLevelUsed` field. The `helpLevelWeight` function had no default
case in its switch statement, returning `undefined` when called with
undefined, which caused `undefined * rtWeight = NaN` to propagate
through BKT calculations.
Changes:
- evidence-quality.ts: Add default case returning 1.0 for undefined/null
and add NaN guard to responseTimeWeight
- bkt-core.ts: Add NaN guards that surface invalid data with console.warn
- conjunctive-bkt.ts: Add NaN guards for multi-skill BKT updates
- compute-bkt.ts: Skip problem results that would produce NaN, preserving
prior state rather than corrupting skill estimates
- bkt-integration.ts: Add NaN guard to calculateBktMultiplier with
conservative fallback
- DashboardClient.tsx: Add UI error state for NaN pKnown values showing
"⚠️ Data Error" instead of displaying "~NaN%"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove view mode toggle (Compact/Detailed) - confusing UX
- Add problem numbers (#1, #2...) to compact view for easy reference
- Make each problem tappable to open detail popover
- Popover shows: equation, student answer if wrong, response time,
pause threshold, help level, abacus usage, skills exercised
- Close popover with tap outside, X button, or Escape key
Users can now see all problems at a glance with numbers, and tap any
specific problem to get the full details without losing their place.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace horizontal rows in stale skills section with SkillCard grid
- Move "Mark Current" action into SkillDetailDrawer for stale skills
- Add staleness alert section in drawer with explanation and action
- Consistent visual presentation between practicing and stale skills
- User can now tap any stale skill to see details and mark as current
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Make StudentFilterBar fixed below nav with proper z-index layering
- Add sticky bucket headers (Today, This Week, etc.) and category headers
- Move bulk actions into filter bar (shown in edit mode in place of search)
- Create shared EmojiPicker component with emojibase-data integration
- Simplify AddStudentModal to use shared EmojiPicker (single way to pick emoji)
- Add z-index constants for filter bar and sticky headers
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The dashboard fetches skills from /api/curriculum/[playerId] which was
returning raw playerSkillMastery records with persisted attempts/correct
values (always 0 for seeded data).
Updated the API to compute skill stats from session results, consistent
with the recent single-source-of-truth refactor.
🤖 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>
ProblemToReview component improvements:
- Use AnnotatedProblem for unified collapsed/expanded problem display
- Integrate BKT mastery data for weak skill detection and ordering
- Add smooth CSS Grid animations for expand/collapse transitions
- Make header row clickable (toggle moved from footer to header)
- Add purpose explanations and timing info in expanded mode
- Show up to 3 weak skills in collapsed mode with "+N more" indicator
React Query cache fix:
- Fix "Mark Current" button not updating UI (stale cache issue)
- Replace plain fetch + router.refresh() with useRefreshSkillRecency mutation
- Mutation properly invalidates curriculumKeys.detail(playerId)
Documentation:
- Add CLAUDE.md section on React Query mutation patterns
- Document the relationship between mutations and query cache invalidation
- Include checklist to prevent future cache invalidation bugs
🤖 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>
Remove unimplemented features that didn't actually save data:
- Placement test: UI worked but results were never persisted
- Offline session recording: form collected data but just logged it
- View Progress button: was an empty callback
- Worksheet button: redirected but didn't integrate with practice
Add functional stale skills management:
- Add "Mark Current" refresh buttons to Skills tab stale skills section
- Show BKT status badges and staleness warnings
- Wire up refresh API to update skill recency
Clean up dead code:
- Delete SkillsClient.tsx (was unused, /skills redirects to dashboard)
- Remove onRefreshSkill from ManualSkillSelector modal
- Add BKT badges to ManualSkillSelector for skill status visibility
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>