Commit Graph

3104 Commits

Author SHA1 Message Date
Thomas Hallock 446678799c refactor(help): simplify to binary help system + add seed script CLI
Help System Cleanup:
- Simplify HelpLevel from 0|1|2|3 to binary 0|1 (matching actual usage)
- Change BKT help weight from 0.8 to 0.5 for helped answers
- Delete unused PracticeHelpPanel.tsx (~540 lines)
- Delete unused usePracticeHelp.ts (~400 lines)
- Delete unused reinforcement-config.ts
- Remove reinforcement tracking (BKT handles skill weakness detection)
- Update all journey simulator profiles to use binary help arrays
- Update documentation (BKT_DESIGN_SPEC.md, decomposition README)

Seed Script Improvements:
- Add CLI argument parsing with node:util parseArgs
- Add --help, --list, --name, --category, --dry-run flags
- Add new "Forgotten Weaknesses" test profile (weak + stale skill mix)
- Enable seeding individual students or categories

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 06:28:27 -06:00
github-actions[bot] b9d4bc552a 🎨 Update template examples and crop mark gallery
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>
2025-12-21 02:41:19 +00:00
Thomas Hallock 7d03d8c69b test(seed): update NaN stress test to cover missing helpLevelUsed root cause
- 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>
2025-12-20 14:44:15 -06:00
Thomas Hallock f883fbfe23 feat(seed): add category field to all mock student profiles
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>
2025-12-20 14:36:56 -06:00
Thomas Hallock b300ed9f5c fix(bkt): handle missing helpLevelUsed in legacy data causing NaN
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>
2025-12-20 14:31:47 -06:00
Thomas Hallock f760ec130e refactor(summary): replace compact/detailed toggle with tap-for-details popover
- 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>
2025-12-20 13:55:57 -06:00
Thomas Hallock d6c8e582a7 refactor(skills): unify skill presentation with SkillCard grid
- 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>
2025-12-20 13:16:35 -06:00
Thomas Hallock 0e0356113d feat(practice): add fixed filter bar, sticky headers, and shared EmojiPicker
- 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>
2025-12-20 12:17:12 -06:00
Thomas Hallock 538718a814 feat(practice): add student organization with filtering and archiving
Implements comprehensive student organization system for /practice page:

Database:
- Add isArchived column to players table (migration 0039)
- Drop unused skill stat columns from playerSkillMastery (migration 0038)

New features:
- Search bar for filtering by student name or skill
- Skill filter pills with AND logic
- Hierarchical grouping: recency buckets → skill categories
- Archive/unarchive from notes modal
- Edit mode with bulk checkbox selection
- Bulk archive for selected students
- Show/hide archived students toggle

New files:
- src/constants/skillCategories.ts - shared skill category definitions
- src/utils/studentGrouping.ts - grouping/filtering logic
- src/utils/skillSearch.ts - skill search utilities
- src/components/practice/StudentFilterBar.tsx - filter bar component

Updated:
- PracticeClient.tsx - filter state management, grouped display
- StudentSelector.tsx - edit mode, archived badges
- NotesModal.tsx - archive button in footer
- ManualSkillSelector.tsx - uses shared skill categories
- server.ts - getPlayersWithSkillData() for enhanced queries

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 10:37:34 -06:00
Thomas Hallock 11d48465d7 fix(dashboard): compute skill stats from session results in curriculum API
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>
2025-12-20 09:39:38 -06:00
Thomas Hallock f804d24a29 refactor(skills): compute skill stats from session results (single source of truth)
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>
2025-12-20 09:31:16 -06:00
Thomas Hallock 35720820f3 refactor(seeder): reframe problematic profiles for realistic data generation
- 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>
2025-12-20 09:10:34 -06:00
Thomas Hallock 430c46adb9 feat(session-summary): redesign ProblemToReview with BKT integration and animations
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>
2025-12-20 07:31:43 -06:00
semantic-release-bot 05aa87ffd2 chore(abacus-react): release v2.17.0 [skip ci]
# [2.17.0](https://github.com/antialias/soroban-abacus-flashcards/compare/abacus-react-v2.16.0...abacus-react-v2.17.0) (2025-12-20)

### Bug Fixes

* **modal:** expand settings by default on tall phones to fill space ([2ffb71a](2ffb71ab28))
* **modal:** make StartPracticeModal full-screen on mobile phones ([1383db8](1383db8185))

### Features

* **banner:** add scroll-based projection with FLIP animation ([d405038](d405038711))
* **modal:** redesign StartPracticeModal layout for tall phones ([0e2fcee](0e2fcee0ae))
* **practice:** unify session resume/start into projecting banner ([d128e80](d128e808db))
* **session-summary:** unify summary and debug views with progressive disclosure ([2977bd5](2977bd57df))
2025-12-20 03:16:36 +00:00
Thomas Hallock 2977bd57df feat(session-summary): unify summary and debug views with progressive disclosure
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>
2025-12-19 21:15:14 -06:00
Thomas Hallock 4b291b304b refactor(practice): remove stub features and add stale skills refresh
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>
2025-12-19 20:30:02 -06:00
Thomas Hallock aef5fadf86 refactor: remove fluency system terminology from comments
Replace outdated "fluency-based" and "fluency multipliers" terminology
with "discrete multipliers (practicing/not_practicing)" throughout
the codebase. BKT now handles fine-grained mastery estimation.

Changes:
- Update bkt-integration.ts mode descriptions
- Update complexity-budgets.ts mode comparison comments
- Update skillComplexity.ts calculator documentation
- Update useSessionPlan.ts hook parameter descriptions
- Update progress-manager.ts and API route comments
- Update comprehensive A/B test documentation
- Update skillComplexity.test.ts to test 2-state model

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 13:28:49 -06:00
Thomas Hallock d405038711 feat(banner): add scroll-based projection with FLIP animation
- Banner projects from content area to nav when scrolled under sticky header
- Uses IntersectionObserver to detect when content banner scrolls out of view
- FLIP animation smoothly transitions between slots with spring physics
- Preserves content slot space when projecting to prevent layout jump
- Uses react-use-measure for accurate dimension tracking
- Animates both position and size (width/height) between variants
- Nav slot collapses to height:0 when content slot is active
- Animation overlay uses higher z-index to appear above sticky nav

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 10:17:47 -06:00
Thomas Hallock 0c40c28a9a refactor(banner): implement FLIP animation for document-flow banners
Replace fixed-position ProjectingBanner with FLIP-based BannerSlots:

- Banners now render in document flow (relative positioning)
- Content flows naturally around banners
- FLIP animation only uses fixed positioning during ~400ms transition
- After animation, banner returns to document flow at target slot

Architecture:
- ContentBannerSlot/NavBannerSlot: Render content in-flow when active
- ProjectingBanner: Orchestrates FLIP animation during slot transitions
- Uses framer-motion springs for smooth position/size interpolation

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 09:13:53 -06:00
Thomas Hallock d128e808db feat(practice): unify session resume/start into projecting banner
Consolidates two competing CTAs (resume button in dashboard vs practice
button in banner) into a single unified experience in the session banner.

When an active session exists, the projecting banner now shows:
- Session progress (X/Y problems completed)
- When started / last activity timestamps
- Focus description and skill changes since session start
- "Resume Session" button to continue where left off
- "Start Fresh" link to open modal (session only abandoned when new one starts)

Changes:
- Add ActiveSessionBanner component with dashboard and nav variants
- Add computeSkillChanges utility for tracking skill state changes
- Extend SessionModeBannerContext with activeSession state and handlers
- Modify ProjectingBanner to conditionally render ActiveSessionBanner
- Remove resume button and activeSession prop from ProgressDashboard
- Wire up active session data in DashboardClient

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 08:08:36 -06:00
Thomas Hallock 9abf29d9fc refactor(modal): simplify StartPracticeModal layout to single responsive design
- Remove all "tall phone" media queries (@media max-width: 480px and min-height: 700px)
- Remove useEffect that auto-expanded settings on tall phones
- Use CSS order: 99 on session-config to always show CTAs first, settings last
- Remove redundant header section (🎯 Ready to practice?) - CTAs provide context
- Keep Dialog.Title/Description as sr-only for accessibility
- Simplify to just 2 layouts: default and landscape mode
- Format SessionProgressIndicator.stories.tsx

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 07:06:45 -06:00
Thomas Hallock 2ffb71ab28 fix(modal): expand settings by default on tall phones to fill space
- Settings now expand automatically on tall phones (height >= 700px)
- Increased gap between sections (1rem -> 1.5rem)
- Restored normal padding and gaps inside expanded settings
- Larger labels and button gaps in settings on tall phones

This fills the empty space by showing all settings expanded,
making the layout feel intentional rather than sparse.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 06:44:29 -06:00
Thomas Hallock 0e2fcee0ae feat(modal): redesign StartPracticeModal layout for tall phones
On tall phones (width ≤ 480px AND height ≥ 700px):
- Reorder content: hero CTA banner first, settings second (CSS order)
- Hero CTA (tutorial/remediation/generic) is larger, centered, more prominent
  - 2.5rem emoji, 1.125rem title, generous padding
  - Centered vertical layout with skill badges
- Session settings appear below as secondary option
- Title and icon restored to full size
- Generous spacing creates intentional, designed appearance
- Content vertically centered with balanced whitespace

Fixes the "empty middle gap" issue where settings were at top
and CTA was pushed to bottom with marginTop: auto.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 06:41:38 -06:00
Thomas Hallock 1383db8185 fix(modal): make StartPracticeModal full-screen on mobile phones
The modal was only going full-screen based on max-height: 700px,
which didn't trigger on iPhone 14 (844px height). Now also triggers
on max-width: 480px to cover all phone-sized screens.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 20:09:49 -06:00
Thomas Hallock 6a98f6af95 chore: remove unused SkillUnlockBanner component
Superseded by CelebrationProgressionBanner which is integrated
into SessionModeBanner and handles skill unlock celebrations.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 20:07:59 -06:00
semantic-release-bot 8f8af92286 chore(abacus-react): release v2.16.0 [skip ci]
# [2.16.0](https://github.com/antialias/soroban-abacus-flashcards/compare/abacus-react-v2.15.0...abacus-react-v2.16.0) (2025-12-19)

### Bug Fixes

* **blog:** correct misleading claim about BKT feeding problem generation ([184cba0](184cba0ec8))
* **blog:** regenerate trajectory data from correct snapshot ([ce85565](ce85565f06))
* **dashboard:** make student dashboard responsive for small screens ([129907f](129907fcc6))
* **dashboard:** use React Query mutations instead of direct fetch ([ff7554b](ff7554b005))
* **migration:** add statement-breakpoint between CREATE and INSERT ([ba68cfc](ba68cfc75d))
* **practice:** add comprehensive logging and validation in recordSlotResult ([85d36c8](85d36c80a2))
* **practice:** add defensive checks in recordSlotResult ([a33e3e6](a33e3e6d2b))
* **practice:** add responsive styles to SessionModeBanner for small screens ([be08efe](be08efe06f))
* **practice:** check all later prefix sums for ambiguity, not just final answer ([43e7db4](43e7db4e88))
* **practice:** correct five complement skill detection for addition and subtraction ([1139c4d](1139c4d1a1))
* **practice:** correct pause phrase attribution ([cc5bb47](cc5bb479c6))
* **practice:** correct route path for resume session ([1a7945d](1a7945dd0b))
* **practice:** disable auto-scroll and add modern PWA meta tag ([8a9afa8](8a9afa86bc))
* **practice:** ensure badges are never taller than wide ([5730bd6](5730bd6112))
* **practice:** ensure keypad spans full screen width ([4b8cbdf](4b8cbdf83c))
* **practice:** ensure speed meter bar is always visible ([0c40dd5](0c40dd5c42))
* **practice:** fix circular import causing REINFORCEMENT_CONFIG.creditMultipliers to be undefined ([147974a](147974a9f0))
* **practice:** fix invisible resume button by using inline styles ([dd3dd45](dd3dd4507c))
* **practice:** handle paused state transitions and add complete phase ([36c9ec3](36c9ec3301))
* **practice:** improve dark mode contrast for sub-nav buttons ([59f574c](59f574c178))
* **practice:** improve mobile layout + floating abacus positioning ([3c9406a](3c9406afc5))
* **practice:** include endEarly.data in currentPlan priority chain ([28b3b30](28b3b30da6))
* **practice:** make session plan page self-sufficient for data loading ([7243502](7243502873))
* **practice:** move SessionPausedModal into ActiveSession for single pause state ([f0a9608](f0a9608a6b))
* **practice:** only show landscape keypad on phone-sized screens ([6c09976](6c09976d4b))
* **practice:** prevent keypad from covering nav and content ([839171c](839171c0ff))
* **practice:** prevent stray "0" rendering in problem area ([7a2390b](7a2390bd1b))
* **practice:** remove empty spacer button from keypad layout ([1058f41](1058f411c6))
* **practice:** remove fallback random problem generation ([f95456d](f95456dadc))
* **practice:** size answer boxes for intermediate prefix sums ([5cfbeeb](5cfbeeb8df))
* **practice:** state-aware complexity selection with graceful fallback ([6c88dcf](6c88dcfdc5))
* **practice:** update pun to "We pressed paws!" ([4800a48](4800a48128))
* **practice:** use inline styles for progress bar ([f45428e](f45428ed82))
* **practice:** use raw CSS media query for landscape keypad visibility ([31fbf80](31fbf80b8f))
* **practice:** use React Query cache for /resume page session data ([ae1a0a8](ae1a0a8e2d))
* **StartPracticeModal:** responsive improvements + integrated tutorial CTA ([56742c5](56742c511d))
* sync pause state between modal and ActiveSession ([55e5c12](55e5c121f1))

### Features

* **abacus:** add dockable abacus feature for practice sessions ([5fb4751](5fb4751728))
* **abacus:** add smooth animated transitions for dock/undock ([2c832c7](2c832c7944))
* **bkt:** add adaptive-bkt mode with unified BKT architecture ([7085a4b](7085a4b3df))
* **bkt:** implement adaptive skill targeting with validated convergence ([354ada5](354ada596d))
* **blog:** add Bayesian blame attribution validation and address reviewer feedback ([ceadd9d](ceadd9de67))
* **blog:** add interactive ECharts for BKT validation blog post ([6a4dd69](6a4dd694a2))
* **blog:** add layered skill trajectory visualization ([b227162](b227162da6))
* **blog:** add session 0, line thickness, and category averages to charts ([c40baee](c40baee43f))
* **blog:** show adaptive vs classic comparison on same chart ([b0c0f5c](b0c0f5c2da))
* **blog:** simplify All Skills chart to show average comparison ([6ef329d](6ef329dd60))
* **practice:** add "Press paws!" pun to auto-pause phrases ([8405f64](8405f64486))
* **practice:** add /resume route for "Welcome back" experience ([7b476e8](7b476e80c1))
* **practice:** add 30 and 45 minute session duration options ([e42766c](e42766c893))
* **practice:** add auto-pause and improve docked abacus sizing ([9c1fd85](9c1fd85ed5))
* **practice:** add browse mode navigation and improve SpeedMeter timing display ([3c52e60](3c52e607b3))
* **practice:** add cascading regrouping skills and improve help UX ([7cf689c](7cf689c3d9))
* **practice:** add celebration progression banner with smooth transitions ([bb9506b](bb9506b93e))
* **practice:** add complexity budget system and toggleable session parts ([5d61de4](5d61de4bf6))
* **practice:** add inline practice panel for browse mode debugging ([c0764cc](c0764ccd85))
* **practice:** add pause info with response time statistics to paused modal ([826c849](826c8490ba))
* **practice:** add play emoji to Keep Going button ([80a33bc](80a33bcae2))
* **practice:** add prefix sum disambiguation and debug panel ([46ff5f5](46ff5f528a))
* **practice:** add projecting SessionModeBanner with slot-based animation ([0f84ede](0f84edec0a))
* **practice:** add Remediation CTA for weak skill focus sessions ([7d8bb2f](7d8bb2f525))
* **practice:** add response time tracking and live timing display ([18ce1f4](18ce1f41af))
* **practice:** add SkillUnlockBanner + session summary improvements ([4daf7b7](4daf7b7433))
* **practice:** add student notes with animated modal + BKT improvements ([2702ec5](2702ec585f))
* **practice:** add subtraction support to problem generator ([4f7a9d7](4f7a9d76cd))
* **practice:** add unified SessionMode system for consistent skill targeting ([b345baf](b345baf3c4))
* **practice:** consolidate nav with transport dropdown and mood indicator ([8851be5](8851be5948))
* **practice:** improve docked abacus UX and submit button behavior ([60fc81b](60fc81bc2d))
* **practice:** improve help mode UX with crossfade and dismiss behaviors ([bcb1c7a](bcb1c7a173))
* **practice:** improve modal UI with problem counts and time estimation ([34d0232](34d0232451))
* **practice:** improve session summary UI ([a27fb0c](a27fb0c9a4))
* **practice:** inline emoji with random pause phrases ([c13fedd](c13feddfbb))
* **practice:** integrate timing display into sub-nav with mobile support ([2fca17a](2fca17a58b))
* **practice:** migrate mastery model to isPracticing + computed fluency ([b2e7268](b2e7268e7a))
* **practice:** redesign paused modal with kid-friendly statistics UX ([11ecb38](11ecb385ad))
* **practice:** reduce term count for visualization part ([9159608](9159608dcd))
* **practice:** refactor disambiguation into state machine with comprehensive tests ([ed277ef](ed277ef745))
* **practice:** responsive mobile keypad and unified skill detection ([ee8dccd](ee8dccd83a))
* **practice:** separate phrase sets for manual vs auto pause ([652519f](652519f219))
* **practice:** unify dashboard with session-aware progress display ([c40543a](c40543ac64))
* **practice:** use student's actual mastered skills for problem generation ([245cc26](245cc269fe))
* **session-planner:** integrate SessionMode for single source of truth targeting ([9851c01](9851c01026))
* **skills-modal:** add spring animations and UX improvements ([b94f533](b94f5338e5))
* **skills:** add Skills Dashboard with honest skill assessment framing ([bf4334b](bf4334b281))
* **test:** add journey simulator for BKT A/B testing ([86cd518](86cd518c39))
* **tutorial:** implement subtraction in unified step generator ([e5c697b](e5c697b7a8))
2025-12-19 01:51:28 +00:00
Thomas Hallock 3c9406afc5 fix(practice): improve mobile layout + floating abacus positioning
- Add bottomOffset/rightOffset to MyAbacusContext for virtual keyboard avoidance
- NumericKeypad sets offsets when mounted (48px bottom, 100px right)
- Floating abacus repositions above/beside keyboard in portrait/landscape
- PracticeSubNav: fix horizontal overflow with minWidth: 0 on flex children
- SessionProgressIndicator: allow proper flex shrinking
- ActiveSession: reduce padding/gaps, use flex layout to fill available space
- PracticeClient: use fixed positioning with proper insets for all orientations
  - Portrait: bottom 48px for keypad
  - Landscape: right 100px for keypad
  - Desktop: no offsets needed
- Prevent viewport scrolling during practice sessions

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 19:49:59 -06:00
Thomas Hallock 0f84edec0a feat(practice): add projecting SessionModeBanner with slot-based animation
Implements a unified banner that seamlessly animates between positions:
- Full banner in content area (Dashboard, Summary pages)
- Compact banner in nav slot (other practice pages)
- Smooth React Spring animation when navigating between pages

New files:
- SessionModeBannerContext: manages slot registration and bounds tracking
- ProjectingBanner: animated portal banner using React Spring
- CompactBanner: condensed single-line variant for nav slot
- PracticeLayout: wrapper component with provider
- ProjectingBanner.stories: interactive demos showcasing transitions

Modified:
- PracticeSubNav: removed Start Practice button, added NavBannerSlot
- DashboardClient/SummaryClient: wrapped with provider, use ContentBannerSlot
- zIndex constants: added SESSION_MODE_BANNER layer

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 17:02:31 -06:00
Thomas Hallock 4daf7b7433 feat(practice): add SkillUnlockBanner + session summary improvements
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>
2025-12-18 15:16:34 -06:00
Thomas Hallock be08efe06f fix(practice): add responsive styles to SessionModeBanner for small screens
Add @media (max-width: 400px) breakpoints to all three banner components:
- RemediationBanner: smaller padding, icon size, font sizes, button
- ProgressionBanner: smaller padding, icon size, font sizes, button
- MaintenanceBanner: smaller padding, icon size, font sizes, button

Also adds minWidth: 0 to text containers to prevent overflow on small screens.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 14:58:46 -06:00
Thomas Hallock e9f9aaca16 refactor(practice): remove redundant targeting sections from modal
Now that the Remediation CTA prominently displays weak skills,
the duplicate "Targeting:" and "Focusing on weak skills:" sections
in the config panel are no longer needed.

Removed:
- Target skills summary in collapsed view
- Target skills info in expanded config panel
- Unused targetSkillsInfo useMemo

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 14:47:08 -06:00
Thomas Hallock 7d8bb2f525 feat(practice): add Remediation CTA for weak skill focus sessions
When a student is in remediation mode (has weak skills to strengthen),
the StartPracticeModal now shows a special amber-themed CTA similar to
the tutorial CTA:

- 💪 "Time to build strength!" heading
- Lists weak skills with pKnown percentages
- "Start Focus Practice →" amber button
- Shows up to 4 skills with "+N more" overflow

Includes Storybook stories for:
- Single weak skill
- Multiple weak skills (2)
- Many weak skills (6, with overflow)
- Dark theme variant

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 14:42:44 -06:00
Thomas Hallock 9851c01026 feat(session-planner): integrate SessionMode for single source of truth targeting
The session planner now accepts an optional sessionMode parameter that:
- Uses pre-computed weak skills from SessionMode (remediation mode)
- Eliminates duplicate BKT computation between UI and problem generation
- Ensures "no rug-pulling" - what the modal shows is what configures problems

Changes:
- session-planner.ts: Accept sessionMode, use getWeakSkillIds() when provided
- useSessionPlan.ts: Accept sessionMode in generateSessionPlan function
- plans/route.ts: Pass sessionMode from request body to planner
- StartPracticeModal.tsx: Pass sessionMode when generating plan
- index.ts: Export SessionMode types from curriculum module

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 14:06:42 -06:00
Thomas Hallock b345baf3c4 feat(practice): add unified SessionMode system for consistent skill targeting
Creates a single source of truth for practice session decisions:
- SessionMode types: remediation, progression, maintenance
- getSessionMode() centralizes BKT computation
- SessionModeBanner component displays context-aware messaging
- useSessionMode() hook for React Query integration

Updates Dashboard, Summary, and StartPracticeModal to use SessionMode,
eliminating the "three-way messaging" problem where different parts of
the UI showed conflicting skill information.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 13:56:15 -06:00
Thomas Hallock bb9506b93e feat(practice): add celebration progression banner with smooth transitions
Adds interpolation utilities and a celebration banner component that
smoothly morphs between celebration and normal states over 60 seconds.

🤫

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 13:42:29 -06:00
Thomas Hallock 56742c511d fix(StartPracticeModal): responsive improvements + integrated tutorial CTA
- Full-screen mode at ≤700px height for iPhone SE support
- Two-column grid layout for settings in landscape mode
- Integrated tutorial CTA: combines unlock banner + start button
- Fixed collapsed mode clipping of target skills section
- Made "focusing on weak skills" visible on all screen sizes
- Fixed duplicate CSS media query breakpoints
- BKT: changed computeBktFromHistory to accept Partial<BktComputeExtendedOptions>

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 10:49:49 -06:00
Thomas Hallock 5735ff0810 docs: add drizzle statement-breakpoint lesson to CLAUDE.md
Documents the critical requirement for --> statement-breakpoint markers
between multiple SQL statements in drizzle migrations. References the
2025-12-18 production outage caused by missing breakpoint.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 07:37:00 -06:00
Thomas Hallock ba68cfc75d fix(migration): add statement-breakpoint between CREATE and INSERT
Drizzle's better-sqlite3 driver requires --> statement-breakpoint
markers between SQL statements in migration files.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 07:18:50 -06:00
Thomas Hallock 129907fcc6 fix(dashboard): make student dashboard responsive for small screens
- Tabs stack vertically on mobile (icon above label) instead of hiding labels
- Summary cards use 2x2 grid on mobile, 4x1 on tablet+
- Skill card grids use smaller min-width on mobile (120px vs 140px)
- Reduced padding throughout on mobile screens
- Section headers and buttons stack vertically on mobile
- History and Notes tabs use responsive padding and font sizes

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 06:45:26 -06:00
Thomas Hallock 2702ec585f feat(practice): add student notes with animated modal + BKT improvements
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>
2025-12-18 06:39:04 -06:00
Thomas Hallock b94f5338e5 feat(skills-modal): add spring animations and UX improvements
- Add smooth spring-animated accordion expand/collapse using react-spring
- Add dynamic scroll indicators that show when content is scrolled
- Auto-scroll to show expanded category content optimally
- Replace ambiguous arrows with "Show/Hide" + rotating chevron
- Make modal full-screen on mobile, centered on desktop
- Add sticky category headers within scroll container
- Fix z-index layering using shared constants
- Add optimistic updates for skill mutations (instant UI feedback)
- Fix React Query cache sync for live skill updates

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 07:23:14 -06:00
Thomas Hallock fad386f216 refactor(know-your-world): use react-use-measure for safe scale calculation
Replace manual useLayoutEffect + resize listener with react-use-measure
hook for cleaner reactive measurement of takeover container bounds.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 07:22:21 -06:00
Thomas Hallock ceadd9de67 feat(blog): add Bayesian blame attribution validation and address reviewer feedback
- Add proper Bayesian inference implementation alongside heuristic approximation
- Create blame-attribution.test.ts with multi-seed validation (5 seeds × 3 profiles)
- Result: No significant difference (t=-0.41, p>0.05), heuristic wins 3/5

Blog post improvements addressing expert reviewer feedback:
- Add Limitations section (simulation-only validation, technique bypass, independence assumption)
- Add "Why We Built This" section explaining automatic proctoring context
- Soften claims: "validate" → "suggest...may...pending real-world confirmation"
- Commit to follow-up publication with real student data
- Add BlameAttribution interactive chart with comparison data

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 19:04:07 -06:00
Thomas Hallock ff7554b005 fix(dashboard): use React Query mutations instead of direct fetch
DashboardClient had 3 direct fetch() calls that bypassed React Query:
- handleStartOver (abandon session)
- handleSaveManualSkills (set mastered skills)
- handleRefreshSkill (refresh skill recency)

These used router.refresh() to update data, which didn't reliably
update the React Query cache, causing stale UI state.

Fix:
- Add useSetMasteredSkills and useRefreshSkillRecency hooks
- Use useActiveSessionPlan with server props as initial data
- Replace direct fetch with mutation hooks
- Remove router.refresh() calls - React Query handles cache invalidation

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 15:31:32 -06:00
Thomas Hallock c40baee43f feat(blog): add session 0, line thickness, and category averages to charts
- Add session 0 data to show initial mastery state before practice
- Single Skill tab: line thickness based on skill tier, category average toggles
- All Skills tab: session 0 for ghost lines and averages
- Fix broken GitHub link (was placeholder "...")
- Add source code links to test files that generate chart data

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 14:05:50 -06:00
Thomas Hallock b227162da6 feat(blog): add layered skill trajectory visualization
New chart design with multiple visual encodings:
- Ghost lines (40% opacity) show individual skill trajectories
- Green spectrum for Adaptive, gray spectrum for Classic
- Darker shades = later in pedagogical sequence
- Line thickness encodes skill difficulty:
  - 1px: basic skills
  - 1.5px: five-complements
  - 2px: ten-complements (friends of 10)
  - 2.5px: cascading/multi-place regrouping
  - 4px: average line (full opacity, on top)
- Clear legend showing Adaptive (avg) vs Classic (avg)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 13:58:25 -06:00
Thomas Hallock 6ef329dd60 feat(blog): simplify All Skills chart to show average comparison
Replaced cluttered 12-line chart with clean 2-line comparison:
- Green line: Average mastery across all skills (Adaptive mode)
- Gray line: Average mastery across all skills (Classic mode)
- Clear legend with Adaptive/Classic labels
- Area fill for visual distinction
- Tooltip shows both values plus advantage in pp

Much easier to see that Adaptive consistently outpaces Classic.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 13:36:48 -06:00
Thomas Hallock df9f23d2a3 refactor(blog): use marker comments for chart placement
Changed from heading-based injection to explicit marker comments:
- Markers like <!-- CHART: ValidationResults --> in markdown
- Charts now appear after explanatory text, not directly under headings
- Gives explicit control over chart placement in the document flow

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 13:34:30 -06:00
Thomas Hallock b0c0f5c2da feat(blog): show adaptive vs classic comparison on same chart
Changed "All Skills" tab to display both modes simultaneously:
- Solid lines = Adaptive mode (with circle markers)
- Dashed lines = Classic mode (no markers)
- Same color = same skill
- Tooltip shows both values with diff highlighted

This makes comparison much easier than toggling between modes.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 13:30:10 -06:00
Thomas Hallock ce85565f06 fix(blog): regenerate trajectory data from correct snapshot
The JSON was stale - regenerated from the correct 6-skill A/B test
snapshot showing adaptive wins 4-0 at 50% and 6-0 at 80%.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 13:26:52 -06:00