Commit Graph

3017 Commits

Author SHA1 Message Date
Thomas Hallock 4800a48128 fix(practice): update pun to "We pressed paws!"
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 17:02:16 -06:00
Thomas Hallock 8405f64486 feat(practice): add "Press paws!" pun to auto-pause phrases
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 17:01:16 -06:00
Thomas Hallock c13feddfbb feat(practice): inline emoji with random pause phrases
- Put emoji (🤔/) and phrase on same line in header
- Add random phrases for auto-pause: "This one's a thinker!", "Brain at
  work!", "Deep thoughts happening...", etc.
- Horizontal layout with avatar on left, title/timer on right
- Smaller avatar (56px) for more compact layout

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 17:01:00 -06:00
Thomas Hallock 0ee14a71b6 refactor(practice): simplify paused modal header layout
Consolidate the stacked header elements into a cleaner layout:
- Single title: "This one's a thinker!" or "Break Time!"
- Timer integrated inline below title instead of separate pill
- Removed redundant name repetition and "Taking a Thinking Break!"

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 16:58:21 -06:00
Thomas Hallock 80a33bcae2 feat(practice): add play emoji to Keep Going button
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 16:55:53 -06:00
Thomas Hallock 366a1f4b83 refactor(practice): remove manual pause encouragement message
Remove the "Smart thinking to take a break" element to declutter the
paused modal layout.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 16:55:38 -06:00
Thomas Hallock dd3dd4507c fix(practice): fix invisible resume button by using inline styles
Switch from Panda CSS to inline styles for the resume button to ensure
the green background and white text are properly applied.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 16:55:10 -06:00
Thomas Hallock 883b683463 refactor(practice): replace "hide" text with close button on stats panel
Add an × close button in the top-right corner of the stats visualization
panel instead of toggling "hide" text in the main paragraph.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 16:54:11 -06:00
Thomas Hallock a892902e8a refactor(practice): improve paused modal UX based on feedback
- Remove "We Know Your Rhythm!" heading (creepy)
- Combine explanation text above the bar: "Usually you take X. This one
  took longer, so we paused to check in."
- Hide stats visualization behind low-key "really?" toggle
- Make resume button much more prominent with deeper green, border,
  larger padding, and stronger shadow
- Make "end session" button less prominent with smaller text, muted
  color, and stop emoji

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 16:53:25 -06:00
Thomas Hallock 0d17809330 refactor(practice): remove stats panel for default timeout case
Only show the rhythm/stats panel when we have enough data to display
meaningful statistics. For the default 5-minute timeout case (before
we've collected enough samples), just show the standard pause UI.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 16:49:35 -06:00
Thomas Hallock 3f61dbc0b5 refactor(practice): use Intl.NumberFormat for time duration formatting
Replace hand-rolled duration formatting with Intl.NumberFormat using
the 'unit' style. This leverages browser-native localization for
pluralization (1 second vs 2 seconds) and proper formatting.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 16:47:18 -06:00
Thomas Hallock 11ecb385ad feat(practice): redesign paused modal with kid-friendly statistics UX
Redesign SessionPausedModal to be approachable for children while
maintaining high-fidelity statistical information:

- New visual components:
  - SpeedMeter: shows average response time vs variation range
  - SampleDots: visualizes progress toward learning user's rhythm (5 samples)

- Educational framing:
  - "We Know Your Rhythm!" when we have enough samples
  - "Learning Your Rhythm..." when collecting data
  - "Taking a Thinking Break!" instead of clinical "paused" language

- Friendly UI improvements:
  - Contextual emoji thought bubbles (🤔 for auto-pause,  for manual)
  - Encouraging messages ("Smart thinking to take a break!")
  - "Keep Going!" button instead of "Resume"
  - Progress bar with gradient styling

- Statistical transparency:
  - Shows "Usually you take about X seconds" for mean
  - Visual representation of standard deviation as "wiggle room"
  - Explains why the pause happened in child-friendly terms

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 16:46:06 -06:00
Thomas Hallock 826c8490ba feat(practice): add pause info with response time statistics to paused modal
- Add auto-pause when response time exceeds mean + 2σ (or 5min default)
- Track pause reason (manual vs auto-timeout) and timing info
- Display live-updating pause duration counter
- Show statistical details: sample count, mean, std dev, threshold
- For insufficient data, show "need X more problems for personalized timing"
- Add comprehensive Storybook stories for all pause scenarios

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 16:38:17 -06:00
Thomas Hallock 9c1fd85ed5 feat(practice): add auto-pause and improve docked abacus sizing
- Add auto-pause when user takes too long on a problem
  - Uses mean + 2 standard deviations of response times when ≥5 problems
  - Falls back to 5 minute timeout otherwise
  - Clamped between 30 seconds and 5 minutes

- Fix docked abacus to auto-scale to match problem dimensions
  - AbacusDock now uses width: 100% and measured problem height
  - MyAbacus calculates effectiveScaleFactor based on container size
  - Animations use consistent scale calculations

- Fix bug: session paused modal no longer shows on page reload
- Fix bug: help mode now exits when both overlay and panel are dismissed

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 15:01:45 -06:00
Thomas Hallock 60fc81bc2d feat(practice): improve docked abacus UX and submit button behavior
- Force show submit button when abacus is docked (user needs manual submit)
- Disable auto-help when docked; trigger help on submit for prefix sums
- Fix dock animation to measure actual destination position
- Keep problem centered when dock appears/disappears (absolute positioning)
- Use scaleFactor prop for natural abacus sizing instead of manual calculations
- Clean up unused dock size tracking and scale calculation code

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 14:35:15 -06:00
Thomas Hallock 2c832c7944 feat(abacus): add smooth animated transitions for dock/undock
Implement FLIP-style animation for the abacus docking feature:
- Measure viewport positions of button and dock using getBoundingClientRect
- Use react-spring to animate position, size, scale, and border-radius
- Add chromeOpacity spring value to smoothly fade button styling
  (background, border, shadow, backdrop-blur) during transitions
- Animation layer renders as fixed-position overlay during transition
- Docking: button chrome fades out as abacus flies to dock
- Undocking: button chrome fades in as abacus returns to corner

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 14:02:23 -06:00
Thomas Hallock 5fb4751728 feat(abacus): add dockable abacus feature for practice sessions
Add AbacusDock component that allows the floating MyAbacus to dock into
designated areas within the UI:
- New AbacusDock component with configurable props (columns, showNumbers,
  value, defaultValue, onValueChange, interactive, animated)
- MyAbacus can now render as: hero, button, open overlay, or docked
- Click floating button when dock is visible to dock the abacus
- Undock button appears in top-right of docked abacus
- Practice sessions use dock for answer input (auto-submit on correct answer)
- Dock sizing now matches problem height with responsive widths

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 13:37:28 -06:00
Thomas Hallock 1a7945dd0b fix(practice): correct route path for resume session
Change /practice/[studentId]/session to /practice/[studentId] since the
active session page is at the root [studentId] path, not a /session subfolder.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 12:23:04 -06:00
Thomas Hallock 5730bd6112 fix(practice): ensure badges are never taller than wide
Use fixed height with minWidth and pill-shaped border-radius so badges expand horizontally for multi-digit numbers while staying circular for single digits.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 12:04:01 -06:00
Thomas Hallock 34d0232451 feat(practice): improve modal UI with problem counts and time estimation
- Wire up time estimation utility to StartPracticeModal for per-mode problem counts
- Add problem count indicators: underneath emojis in collapsed view, badges on mode boxes in expanded view
- Ensure badges are always circular (aspect-ratio: 1)
- Add full-width progress bar to PracticeSubNav HUD with mode indicator and "X left" display
- Add SessionPausedModal for pause state handling
- Refactor ActiveSession to remove internal HUD (moved to sub-nav)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 12:01:52 -06:00
Thomas Hallock 839171c0ff fix(practice): prevent keypad from covering nav and content
Add CSS to push main content away from the keypad:
- Landscape (small screens): padding-right on body and margin-right on
  nav/header/active-session to avoid the 100px right-side keypad
- Portrait: padding-bottom on body for the bottom keypad

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:25:46 -06:00
Thomas Hallock 6c09976d4b fix(practice): only show landscape keypad on phone-sized screens
Use max-height: 500px constraint to only switch to the two-column
landscape layout on small screens (phones). On tablets and larger
screens in landscape, keep the horizontal bar at the bottom.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:22:28 -06:00
Thomas Hallock 31fbf80b8f fix(practice): use raw CSS media query for landscape keypad visibility
Panda CSS @media queries in object syntax weren't working reliably.
Use raw CSS string with proper @media (orientation: landscape) rule
to toggle between portrait and landscape keypad containers.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:15:51 -06:00
Thomas Hallock 1058f411c6 fix(practice): remove empty spacer button from keypad layout
When submit button isn't shown, omit it entirely from the layout
instead of using a hidden spacer. This lets the remaining buttons
flex to fill the full width.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:07:35 -06:00
Thomas Hallock 4b8cbdf83c fix(practice): ensure keypad spans full screen width
Added explicit width: 100% and max-width: none to override
react-simple-keyboard defaults that may constrain width.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:04:26 -06:00
Thomas Hallock ee8dccd83a feat(practice): responsive mobile keypad and unified skill detection
NumericKeypad improvements:
- Fixed position: bottom bar in portrait, right panel in landscape
- Uses react-simple-keyboard with key-like styling (raised, press effect)
- Persists once shown even if physical keyboard detected

Skill detection refactoring:
- Unified all skill analysis through generateUnifiedInstructionSequence
- Removed ~210 lines of dead column-based analysis code
- Added cascading carry/borrow detection for consecutive ten complements
- Ported test cases from columnAnalysis.test.ts to skillDetection.test.ts

abacus-react:
- Added server-side compatible static exports

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:03:19 -06:00
Thomas Hallock 1139c4d1a1 fix(practice): correct five complement skill detection for addition and subtraction
Fix bugs where five complement skills were incorrectly detected when the
heaven bead was already active:

Addition: When adding 1-4 results in 6-9 and currentDigit >= 5, no five
complement is needed - just add earth beads directly.

Subtraction: When ten complement addition crosses 5 boundary but
currentDigit >= 5, no five complement is needed for the addition part.

Also includes UX improvements from previous session:
- Dream sequence: show target value for 1s then fade out after help completion
- Clear answer boxes on help abacus dismiss
- Handle typing during help mode

Add comprehensive unit tests for column analysis functions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 06:50:57 -06:00
Thomas Hallock bcb1c7a173 feat(practice): improve help mode UX with crossfade and dismiss behaviors
- Add crossfade animation between answer boxes and help abacus (1s enter, 300ms dismiss)
- Preserve user's prefix sum in answer boxes during fade-out transition
- Clear answer boxes after help abacus entrance transition completes
- Add dismiss button to help abacus with tooltip suppression on dismiss
- Add keyboard shortcuts (Escape/Delete/Backspace) to exit help mode
- Typing while in help mode dismisses help and starts fresh input
- Add independent dismiss controls for help abacus and help panel
- Fix tooltip remaining visible when help abacus is dismissed

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 06:06:57 -06:00
Thomas Hallock a27fb0c9a4 feat(practice): improve session summary UI
- Group skills by category (pedagogical order: basic → 5-complements → 10-complements)
- Make skill categories collapsible with aggregate stats in header
- Use vertical layout for abacus/visualization problems (compact workbook style)
- Use horizontal layout for mental math problems (equation format)
- Remove duplicate "Review Answered Problems" section
- Remove "Review Problems" heading (self-evident)
- Fix part names: "Abacus", "Visualize", "Mental Math"

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 05:05:38 -06:00
Thomas Hallock f95456dadc fix(practice): remove fallback random problem generation
Remove the fallback that was silently generating random problems when
skill-based generation failed. Instead, throw ProblemGenerationError
with detailed constraint information so issues can be addressed.

The analyzeRequiredSkills function should only be used for tests or
stories, not in production where we need accurate skill tracking.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 20:56:48 -06:00
Thomas Hallock 5d61de4bf6 feat(practice): add complexity budget system and toggleable session parts
- Add skill complexity budget system with base costs per skill type:
  - Basic skills: 0 (trivial bead movements)
  - Five complements: 1 (single mental substitution)
  - Ten complements: 2 (cross-column operations)
  - Cascading operations: 3 (multi-column)

- Add per-term complexity debug overlay in VerticalProblem (toggle via visual debug mode)
  - Shows total cost per term and individual skill costs
  - Highlights over-budget terms in red

- Make session structure parts toggleable in configure page:
  - Can enable/disable abacus, visualization, and linear parts
  - Time estimates, problem counts adjust dynamically
  - At least one part must remain enabled

- Fix max terms per problem not being respected:
  - generateSingleProblem was hardcoding 3-5 terms
  - Now properly uses minTerms/maxTerms from constraints

- Set visualization complexity budget to 3 (more restrictive)
- Hide complexity badges for zero-cost (basic) skills in ManualSkillSelector

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 20:18:20 -06:00
Thomas Hallock 9159608dcd feat(practice): reduce term count for visualization part
Visualization problems now use 2-4 terms (75% of abacus's 3-6 terms)
to make them easier since students don't have the physical abacus
to help track their mental calculations.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 11:32:19 -06:00
Thomas Hallock 7cf689c3d9 feat(practice): add cascading regrouping skills and improve help UX
- Add advanced.cascadingCarry and advanced.cascadingBorrow skills for
  detecting when carry/borrow propagates across 2+ consecutive columns
  (e.g., 999 + 1 = 1000 or 1000 - 1 = 999)
- Update VerticalProblem help UX: replace answer boxes with help abacus
  instead of floating above terms (less confusing for kids)
- Dim terms already in prefix sum at 40% opacity when in help mode
- Enlarge current-help arrow indicator to 1.75rem
- Add "Advanced Multi-Column Operations" category to ManualSkillSelector
  so teachers can manually enable these skills
- Add unit tests for cascading regrouping detection (21 tests)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 11:19:09 -06:00
Thomas Hallock 5cfbeeb8df fix(practice): size answer boxes for intermediate prefix sums
- Calculate prefix sums (intermediate values) when determining maxDigits
- Ensures kids can enter step-by-step solutions that may be larger than final answer
- Example: 100-99=1 now has 3 answer boxes to accommodate entering "100" first

Also adds Playground story for testing any term sequence with:
- Textarea input with smart parsing of negatives
- Display of all prefix sums and max digits needed
- Interactive answer input

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 10:24:20 -06:00
Thomas Hallock e5c697b7a8 feat(tutorial): implement subtraction in unified step generator
Add complete subtraction support to the decomposition system:

- Direct subtraction: remove beads when sufficient
- Five's complement subtraction: -d = -5 + (5-d)
- Ten's complement subtraction (borrow): -d = +(10-d) - 10
- Multi-digit subtraction with left-to-right processing
- Cascade borrow through consecutive zeros

Also adds:
- Comprehensive architecture documentation
- Subtraction implementation plan with design decisions
- Decomposition audit story for testing all operation types
- Skill extraction functions for subtraction skills

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 09:31:13 -06:00
Thomas Hallock 4f7a9d76cd feat(practice): add subtraction support to problem generator
- Add subtraction problem generation alongside addition
- Generator now uses signed terms (negative = subtraction)
- Update analyzeRequiredSkills to handle mixed operations
- Remove dead generateSkillTrace function (replaced by provenance)
- Add ProblemGeneratorAudit story for debugging skill analysis
- Display subtraction terms in red with proper +/- signs in audit UI

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 08:06:34 -06:00
Thomas Hallock a3e79dac74 chore: sync lockfile with package.json
Regenerate pnpm-lock.yaml to fix CI deployment failure.
The lockfile was out of sync causing "ERR_PNPM_OUTDATED_LOCKFILE"
in GitHub Actions when running with frozen-lockfile.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 07:06:29 -06:00
Thomas Hallock e42766c893 feat(practice): add 30 and 45 minute session duration options
Extends session duration choices from [5, 10, 15, 20] to [5, 10, 15, 20, 30, 45] minutes, allowing for longer practice sessions with more problems.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 21:01:13 -06:00
Thomas Hallock c40543ac64 feat(practice): unify dashboard with session-aware progress display
- Make ProgressDashboard session-aware with single primary CTA
  - No session: "Start Practice →" (blue)
  - Active session: "Resume Practice →" (green) with progress count
  - Single "Start over" link replaces redundant Abandon/Regenerate buttons
- Add skill mismatch warning inline in level card
- Add masteredSkillIds to session_plans for mismatch detection
- Fix getActiveSessionPlan to check completedAt IS NULL (fixes loop bug)
- Remove separate Active Session Card from dashboard (now integrated)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 20:59:53 -06:00
Thomas Hallock 245cc269fe feat(practice): use student's actual mastered skills for problem generation
Major fix: Session planner now uses the student's actual mastered skills
from the database instead of hardcoded phase-based constraints.

Changes:
- Add buildConstraintsFromMasteredSkills() to convert student skill records
  to problem generator constraints
- Session planner fetches mastered skills and passes them to problem generator
- Skills set via ManualSkillSelector now actually affect generated problems
- Remove unused buildChallengeConstraints() function
- Fix findStrugglingSkills() signature (remove unused param)

Also includes supporting changes from previous session:
- Add setMasteredSkills() to progress-manager for persisting skills
- Add PUT endpoint to skills/route.ts for saving mastered skills
- Display mastered skills in session configure preview
- Add "View All Planned Problems" section to SessionSummary
- Sync ManualSkillSelector state when modal opens

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 19:18:48 -06:00
Thomas Hallock c19109758a refactor(practice): remove unnecessary route guards
Routes are now independent views, not exclusive states:
- /dashboard: always accessible (view stats during session)
- /configure: always accessible (prep next session during session)
- /summary: always accessible (shows in-progress partial results,
  completed session, or empty state)

Only /practice/[studentId] retains guards since it requires an
active in-progress session to render a problem.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 15:10:54 -06:00
Thomas Hallock 5ebc743b43 refactor(practice): unify configure page with live session preview
- Restructure practice routes so each route represents valid state
- /practice/[studentId] now ONLY shows the current problem
- New /dashboard route for progress view
- New /summary route with guards (can't view mid-session)
- Combine configure + plan review into single unified page with:
  - Duration selector that updates preview in real-time
  - Live problem count and session structure preview
  - Single "Let's Go!" button that generates + starts session
- Replace two-stage flow with instant feedback UX
- Delete StudentPracticeClient (replaced by simpler PracticeClient)
- Add getMostRecentCompletedSession for summary page

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 14:13:54 -06:00
Thomas Hallock 9c646acc16 style: format practice session files
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 12:48:36 -06:00
Thomas Hallock f74db216da chore: remove abandoned 3d-printing feature
Remove dead code from abandoned 3D printing initiative:
- Delete jobManager.ts (had unbounded memory growth)
- Delete openscad.worker.ts (unused)
- Delete 3D model files from public/
- Remove openscad-wasm-prebuilt dependency
- Clean up doc references

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 12:48:13 -06:00
Thomas Hallock ae1a0a8e2d fix(practice): use React Query cache for /resume page session data
The /resume page was showing stale session data when navigating mid-session.
Now uses useActiveSessionPlan with server props as initialData, so cached
session data from the active practice session takes priority.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 12:48:05 -06:00
Thomas Hallock 28b3b30da6 fix(practice): include endEarly.data in currentPlan priority chain
The stop button wasn't working because endEarly.data was not included
in the currentPlan derivation chain. When the mutation completed with
the updated plan (completedAt set), the view didn't update to 'summary'.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 12:22:15 -06:00
Thomas Hallock 7b476e80c1 feat(practice): add /resume route for "Welcome back" experience
- Create /practice/[studentId]/resume route for returning students
- Student selector navigates to /resume instead of main practice page
- /resume shows "Welcome back" card with session progress
- Clicking "Continue" navigates to /practice/[studentId] (goes straight to practice)
- Clicking "Start Fresh" abandons session and goes to /configure
- Main practice page no longer shows welcome card (goes straight to practicing)
- Reloading mid-session stays in practice (no welcome card)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 12:00:01 -06:00
Thomas Hallock 7243502873 fix(practice): make session plan page self-sufficient for data loading
- Update useActiveSessionPlan to accept initialData from server props
- Page now fetches its own data if cache is empty (no abstraction hole)
- Three loading scenarios handled:
  1. Cache populated (from ConfigureClient mutation): instant display
  2. Cache miss: fetches from API with loading state
  3. Direct page load: uses server props as initialData
- Add loading view while fetching session plan

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 11:52:52 -06:00
Thomas Hallock 8a9afa86bc fix(practice): disable auto-scroll and add modern PWA meta tag
- Add scroll: false to all router.push() calls in practice pages
- Add scroll={false} to Link component in not-found page
- Fixes Next.js warning about auto-scroll with fixed position header
- Add mobile-web-app-capable meta tag alongside deprecated apple-mobile-web-app-capable

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 11:25:53 -06:00
Thomas Hallock 43e7db4e88 fix(practice): check all later prefix sums for ambiguity, not just final answer
Previously, typing "3" for problem [2, 1, 30, 10, 1] with prefix sums
[2, 3, 33, 43, 44] would immediately show help for prefix sum 3 because
the code only checked if "3" was a digit-prefix of the final answer (44).

Now it correctly checks if "3" could be a digit-prefix of ANY later prefix
sum (33 in this case), making it ambiguous and allowing the user to continue
typing "33" to get help for that prefix instead.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 10:48:38 -06:00