b40465ca8a
15 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9245b4e008 |
CLAUDE: Implement Week 7 Task 3 - Result chart abstraction and PD auto mode
Core Implementation: - Added ResultChart abstract base class with get_outcome() method - Implemented calculate_hit_location() helper for hit distribution - 45% pull, 35% center, 20% opposite field - RHB pulls left, LHB pulls right - Groundballs → infield positions, flyouts → outfield positions - Added PlayOutcome.requires_hit_location() helper method - Returns True for groundballs and flyouts only Manual Mode Support: - Added ManualResultChart (passthrough for interface completeness) - Manual mode doesn't use result charts - players submit directly - Added ManualOutcomeSubmission model for WebSocket submissions - Validates PlayOutcome enum values - Validates hit location positions (1B, 2B, SS, 3B, LF, CF, RF, P, C) PD Auto Mode Implementation: - Implemented PdAutoResultChart for automated outcome generation - Coin flip (50/50) to choose batting or pitching card - Gets rating for correct handedness matchup - Builds cumulative distribution from rating percentages - Rolls 1d100 to select outcome - Calculates hit location using handedness and pull rates - Maps rating fields to PlayOutcome enum: - Common: homerun, triple, doubles, singles, walks, strikeouts - Batting-specific: lineouts, popouts, flyout variants, groundout variants - Pitching-specific: uncapped singles/doubles, flyouts by location - Proper error handling when card data missing Testing: - Created 21 comprehensive unit tests (all passing) - Helper function tests (calculate_hit_location) - PlayOutcome helper tests (requires_hit_location) - ManualResultChart tests (NotImplementedError) - PdAutoResultChart tests: - Coin flip distribution (~50/50) - Handedness matchup selection - Cumulative distribution building - Outcome selection from probabilities - Hit location calculation - Error handling for missing cards - Statistical distribution verification (1000 trials) - ManualOutcomeSubmission validation tests - Valid/invalid outcomes - Valid/invalid hit locations - Optional location handling Deferred to Future Tasks: - PlayResolver integration (Phase 6 - Week 7 Task 3B) - Terminal client manual outcome command (Phase 8) - WebSocket handlers for manual submissions (Week 7 Task 6) - Runner advancement logic using hit locations (Week 7 Task 4) Files Modified: - app/config/result_charts.py: Added base class, auto mode, and helpers - app/models/game_models.py: Added ManualOutcomeSubmission model - tests/unit/config/test_result_charts.py: 21 comprehensive tests All tests passing, no regressions. |
||
|
|
c0051d2a65 |
CLAUDE: Fix defensive decision validation for corners_in/infield_in depths
- Updated validators.py to use is_runner_on_third() helper method instead of hardcoded on_base_code values - Fixed DefensiveDecision Pydantic model: infield depths now ['infield_in', 'normal', 'corners_in'] - Fixed DefensiveDecision Pydantic model: outfield depths now ['in', 'normal'] (removed 'back') - Removed invalid double_play depth tests (depth doesn't exist) - Added proper tests for corners_in and infield_in validation (requires runner on third) - All 54 validator tests now passing Changes maintain consistency between Pydantic validation and GameValidator logic. |
||
|
|
95d8703f56 |
CLAUDE: Implement Week 7 Task 1 - Strategic Decision Integration
Enhanced game engine with async decision workflow and AI opponent integration: GameState Model Enhancements: - Added pending_defensive_decision and pending_offensive_decision fields - Added decision_phase tracking (idle, awaiting_defensive, awaiting_offensive, resolving, completed) - Added decision_deadline field for timeout handling - Added is_batting_team_ai() and is_fielding_team_ai() helper methods - Added validator for decision_phase StateManager Enhancements: - Added _pending_decisions dict for asyncio.Future-based decision queue - Added set_pending_decision() to create decision futures - Added await_decision() to wait for decision submission - Added submit_decision() to resolve pending futures - Added cancel_pending_decision() for cleanup GameEngine Enhancements: - Added await_defensive_decision() with AI/human branching and timeout - Added await_offensive_decision() with AI/human branching and timeout - Enhanced submit_defensive_decision() to resolve pending futures - Enhanced submit_offensive_decision() to resolve pending futures - Added DECISION_TIMEOUT constant (30 seconds) AI Opponent (Stub): - Created ai_opponent.py with stub implementations - generate_defensive_decision() returns default "normal" positioning - generate_offensive_decision() returns default "normal" approach - TODO markers for Week 9 full AI logic implementation Integration: - Backward compatible with existing terminal client workflow - New async methods ready for WebSocket integration (Week 7 Task 4) - AI teams get instant decisions, human teams wait with timeout - Default decisions applied on timeout (no game blocking) Testing: - Config tests: 58/58 passing ✅ - Terminal client: Working perfectly ✅ - Existing workflows: Fully compatible ✅ Week 7 Task 1: Complete Next: Task 2 - Decision Validators 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
5d5c13f2b8 |
CLAUDE: Implement Week 6 league configuration and play outcome systems
Week 6 Progress: 75% Complete ## Components Implemented ### 1. League Configuration System ✅ - Created BaseGameConfig abstract class for league-agnostic rules - Implemented SbaConfig and PdConfig with league-specific settings - Immutable configs (frozen=True) with singleton registry - 28 unit tests, all passing Files: - backend/app/config/base_config.py - backend/app/config/league_configs.py - backend/tests/unit/config/test_league_configs.py ### 2. PlayOutcome Enum ✅ - Universal enum for all play outcomes (both SBA and PD) - Helper methods: is_hit(), is_out(), is_uncapped(), is_interrupt() - Supports standard hits, uncapped hits, interrupt plays, ballpark power - 30 unit tests, all passing Files: - backend/app/config/result_charts.py - backend/tests/unit/config/test_play_outcome.py ### 3. Player Model Refinements ✅ - Fixed PdPlayer.id field mapping (player_id → id) - Improved field docstrings for image types - Fixed position checking logic in SBA helper methods - Added safety checks for missing image data Files: - backend/app/models/player_models.py (updated) ### 4. Documentation ✅ - Updated backend/CLAUDE.md with Week 6 section - Documented card-based resolution mechanics - Detailed config system and PlayOutcome usage ## Architecture Decisions 1. **Card-Based Resolution**: Both SBA and PD use same mechanics - 1d6 (column) + 2d6 (row) + 1d20 (split resolution) - PD: Digitized cards with auto-resolution - SBA: Manual entry from physical cards 2. **Immutable Configs**: Prevent accidental modification using Pydantic frozen 3. **Universal PlayOutcome**: Single enum for both leagues reduces duplication ## Testing - Total: 58 tests, all passing - Config tests: 28 - PlayOutcome tests: 30 ## Remaining Work (25%) - Update dice system (check_d20 → chaos_d20) - Integrate PlayOutcome into PlayResolver - Add Play.metadata support for uncapped hits 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
1c32787195 |
CLAUDE: Refactor game models and modularize terminal client
This commit includes cleanup from model refactoring and terminal client
modularization for better code organization and maintainability.
## Game Models Refactor
**Removed RunnerState class:**
- Eliminated separate RunnerState model (was redundant)
- Replaced runners: List[RunnerState] with direct base references:
- on_first: Optional[LineupPlayerState]
- on_second: Optional[LineupPlayerState]
- on_third: Optional[LineupPlayerState]
- Updated helper methods:
- get_runner_at_base() now returns LineupPlayerState directly
- get_all_runners() returns List[Tuple[int, LineupPlayerState]]
- is_runner_on_X() simplified to direct None checks
**Benefits:**
- Matches database structure (plays table has on_first_id, etc.)
- Simpler state management (direct references vs list management)
- Better type safety (LineupPlayerState vs generic runner)
- Easier to work with in game engine logic
**Updated files:**
- app/models/game_models.py - Removed RunnerState, updated GameState
- app/core/play_resolver.py - Use get_all_runners() instead of state.runners
- app/core/validators.py - Updated runner access patterns
- tests/unit/models/test_game_models.py - Updated test assertions
- tests/unit/core/test_play_resolver.py - Updated test data
- tests/unit/core/test_validators.py - Updated test data
## Terminal Client Refactor
**Modularization (DRY principle):**
Created separate modules for better code organization:
1. **terminal_client/commands.py** (10,243 bytes)
- Shared command functions for game operations
- Used by both CLI (main.py) and REPL (repl.py)
- Functions: submit_defensive_decision, submit_offensive_decision,
resolve_play, quick_play_sequence
- Single source of truth for command logic
2. **terminal_client/arg_parser.py** (7,280 bytes)
- Centralized argument parsing and validation
- Handles defensive/offensive decision arguments
- Validates formats (alignment, depths, hold runners, steal attempts)
3. **terminal_client/completions.py** (10,357 bytes)
- TAB completion support for REPL mode
- Command completions, option completions, dynamic completions
- Game ID completions, defensive/offensive option suggestions
4. **terminal_client/help_text.py** (10,839 bytes)
- Centralized help text and command documentation
- Detailed command descriptions
- Usage examples for all commands
**Updated main modules:**
- terminal_client/main.py - Simplified by using shared commands module
- terminal_client/repl.py - Cleaner with shared functions and completions
**Benefits:**
- DRY: Behavior consistent between CLI and REPL modes
- Maintainability: Changes in one place affect both interfaces
- Testability: Can test commands module independently
- Organization: Clear separation of concerns
## Documentation
**New files:**
- app/models/visual_model_relationships.md
- Visual documentation of model relationships
- Helps understand data flow between models
- terminal_client/update_docs/ (6 phase documentation files)
- Phased documentation for terminal client evolution
- Historical context for implementation decisions
## Tests
**New test files:**
- tests/unit/terminal_client/__init__.py
- tests/unit/terminal_client/test_arg_parser.py
- tests/unit/terminal_client/test_commands.py
- tests/unit/terminal_client/test_completions.py
- tests/unit/terminal_client/test_help_text.py
**Updated tests:**
- Integration tests updated for new runner model
- Unit tests updated for model changes
- All tests passing with new structure
## Summary
- ✅ Simplified game state model (removed RunnerState)
- ✅ Better alignment with database structure
- ✅ Modularized terminal client (DRY principle)
- ✅ Shared command logic between CLI and REPL
- ✅ Comprehensive test coverage
- ✅ Improved documentation
Total changes: 26 files modified/created
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
|
||
|
|
aabb90feb5 |
CLAUDE: Implement player models and optimize database queries
This commit includes Week 6 player models implementation and critical performance optimizations discovered during testing. ## Player Models (Week 6 - 50% Complete) **New Files:** - app/models/player_models.py (516 lines) - BasePlayer abstract class with polymorphic interface - SbaPlayer with API parsing factory method - PdPlayer with batting/pitching scouting data support - Supporting models: PdCardset, PdRarity, PdBattingCard, PdPitchingCard - tests/unit/models/test_player_models.py (692 lines) - 32 comprehensive unit tests, all passing - Tests for BasePlayer, SbaPlayer, PdPlayer, polymorphism **Architecture:** - Simplified single-layer approach vs planned two-layer - Factory methods handle API → Game transformation directly - SbaPlayer.from_api_response(data) - parses SBA API inline - PdPlayer.from_api_response(player_data, batting_data, pitching_data) - Full Pydantic validation, type safety, and polymorphism ## Performance Optimizations **Database Query Reduction (60% fewer queries per play):** - Before: 5 queries per play (INSERT play, SELECT play with JOINs, SELECT games, 2x SELECT lineups) - After: 2 queries per play (INSERT play, UPDATE games conditionally) Changes: 1. Lineup caching (game_engine.py:384-425) - Check state_manager.get_lineup() cache before DB fetch - Eliminates 2 SELECT queries per play 2. Remove unnecessary refresh (operations.py:281-302) - Removed session.refresh(play) after INSERT - Eliminates 1 SELECT with 3 expensive LEFT JOINs 3. Direct UPDATE statement (operations.py:109-165) - Changed update_game_state() to use direct UPDATE - No longer does SELECT + modify + commit 4. Conditional game state updates (game_engine.py:200-217) - Only UPDATE games table when score/inning/status changes - Captures state before/after and compares - ~40-60% fewer updates (many plays don't score) ## Bug Fixes 1. Fixed outs_before tracking (game_engine.py:551) - Was incorrectly calculating: state.outs - result.outs_recorded - Now correctly captures: state.outs (before applying result) - All play records now have accurate out counts 2. Fixed game recovery (state_manager.py:312-314) - AttributeError when recovering: 'GameState' has no attribute 'runners' - Changed to use state.get_all_runners() method - Games can now be properly recovered from database ## Enhanced Terminal Client **Status Display Improvements (terminal_client/display.py:75-97):** - Added "⚠️ WAITING FOR ACTION" section when play is pending - Shows specific guidance: - "The defense needs to submit their decision" → Run defensive [OPTIONS] - "The offense needs to submit their decision" → Run offensive [OPTIONS] - "Ready to resolve play" → Run resolve - Color-coded command hints for better UX ## Documentation Updates **backend/CLAUDE.md:** - Added comprehensive Player Models section (204 lines) - Updated Current Phase status to Week 6 (~50% complete) - Documented all optimizations and bug fixes - Added integration examples and usage patterns **New Files:** - .claude/implementation/week6-status-assessment.md - Comprehensive Week 6 progress review - Architecture decision rationale (single-layer vs two-layer) - Completion status and next priorities - Updated roadmap for remaining Week 6 work ## Test Results - Player models: 32/32 tests passing - All existing tests continue to pass - Performance improvements verified with terminal client ## Next Steps (Week 6 Remaining) 1. Configuration system (BaseConfig, SbaConfig, PdConfig) 2. Result charts & PD play resolution with ratings 3. API client for live roster data (deferred) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
f9aa653c37 |
CLAUDE: Reorganize Week 6 documentation and separate player model specifications
Split player model architecture into dedicated documentation files for clarity and maintainability. Added Phase 1 status tracking and comprehensive player model specs covering API models, game models, mappers, and testing strategy. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
13e924a87c |
CLAUDE: Refactor GameEngine to forward-looking play tracking pattern
Replaced awkward "lookback" pattern with clean "prepare → execute → save" orchestration that captures state snapshots BEFORE each play. Key improvements: - Added per-team batter indices (away_team_batter_idx, home_team_batter_idx) - Added play snapshot fields (current_batter/pitcher/catcher_lineup_id) - Added on_base_code bit field for efficient base situation queries - Created _prepare_next_play() method for snapshot preparation - Refactored start_game() with hard lineup validation requirement - Refactored resolve_play() with explicit 6-step orchestration - Updated _save_play_to_db() to use snapshots (no DB lookbacks) - Enhanced state recovery to rebuild from last play (single query) - Added defensive lineup position validator Benefits: - No special cases for first play - Single source of truth in GameState - Saves 18+ database queries per game - Fast state recovery without replay - Complete runner tracking (before/after positions) - Explicit orchestration (easy to debug) Testing: - Added 3 new test functions (lineup validation, snapshot tracking, batting order) - All 5 test suites passing (100%) - Type checking cleaned up with targeted suppressions for SQLAlchemy Documentation: - Added comprehensive "Type Checking & Common False Positives" section to CLAUDE.md - Created type-checking-guide.md and type-checking-summary.md - Added mypy.ini configuration for SQLAlchemy/Pydantic 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
874e24dc75 |
CLAUDE: Implement comprehensive dice roll system with persistence
Core Implementation: - Created roll_types.py with AbRoll, JumpRoll, FieldingRoll, D20Roll dataclasses - Implemented DiceSystem singleton with cryptographically secure random generation - Added Roll model to db_models.py with JSONB storage for roll history - Implemented save_rolls_batch() and get_rolls_for_game() in database operations Testing: - 27 unit tests for roll type dataclasses (100% passing) - 35 unit tests for dice system (34/35 passing, 1 timing issue) - 16 integration tests for database persistence (uses production DiceSystem) Features: - Unique roll IDs using secrets.token_hex() - League-specific logic (SBA d100 rare plays, PD error-based rare plays) - Automatic derived value calculation (d6_two_total, jump_total, error_total) - Full audit trail with context metadata - Support for batch saving rolls per inning Technical Details: - Fixed dataclass inheritance with kw_only=True for Python 3.13 - Roll data stored as JSONB for flexible querying - Indexed on game_id, roll_type, league_id, team_id for efficient retrieval - Supports filtering by roll type, team, and timestamp ordering Note: Integration tests have async connection pool issue when run together (tests work individually, fixture cleanup needed in follow-up branch) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
8f67883be1 |
CLAUDE: Implement polymorphic Lineup model for PD and SBA leagues
Updated Lineup model to support both leagues using the same pattern as RosterLink: - Made card_id nullable (PD league) - Added player_id nullable (SBA league) - Added XOR CHECK constraint to ensure exactly one ID is populated - Created league-specific methods: add_pd_lineup_card() and add_sba_lineup_player() - Replaced generic create_lineup_entry() with league-specific methods Database migration applied to convert existing schema. Bonus fix: Resolved Pendulum DateTime + asyncpg timezone compatibility issue by using .naive() on all DateTime defaults in Game, Play, and GameSession models. Updated tests to use league-specific lineup methods. Archived migration docs and script to .claude/archive/ for reference. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
3c5055dbf6 |
CLAUDE: Implement polymorphic RosterLink for both PD and SBA leagues
Added league-agnostic roster tracking with single-table design: Database Changes: - Modified RosterLink model with surrogate primary key (id) - Added nullable card_id (PD) and player_id (SBA) columns - Added CHECK constraint ensuring exactly one ID populated (XOR logic) - Added unique constraints for (game_id, card_id) and (game_id, player_id) - Imported CheckConstraint and UniqueConstraint from SQLAlchemy New Files: - app/models/roster_models.py: Pydantic models for type safety - BaseRosterLinkData: Abstract base class - PdRosterLinkData: PD league card-based rosters - SbaRosterLinkData: SBA league player-based rosters - RosterLinkCreate: Request validation model - tests/unit/models/test_roster_models.py: 24 unit tests (all passing) - Tests for PD/SBA roster link creation and validation - Tests for RosterLinkCreate XOR validation - Tests for polymorphic behavior Database Operations: - add_pd_roster_card(): Add PD card to game roster - add_sba_roster_player(): Add SBA player to game roster - get_pd_roster(): Get PD cards with optional team filter - get_sba_roster(): Get SBA players with optional team filter - remove_roster_entry(): Remove roster entry by ID Tests: - Added 12 integration tests for roster operations - Fixed setup_database fixture scope (module → function) Documentation: - Updated backend/CLAUDE.md with RosterLink documentation - Added usage examples and design rationale - Updated Game model relationship description Design Pattern: Single table with application-layer type safety rather than SQLAlchemy polymorphic inheritance. Simpler queries, database-enforced integrity, and Pydantic type safety at application layer. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
c7e8804183 | Resolving pylance error | ||
|
|
a287784328 |
CLAUDE: Complete Week 4 - State Management & Persistence
Implemented hybrid state management system with in-memory game states and async PostgreSQL persistence. This provides the foundation for fast gameplay (<500ms response) with complete state recovery capabilities. ## Components Implemented ### Production Code (3 files, 1,150 lines) - app/models/game_models.py (492 lines) - Pydantic GameState with 20+ helper methods - RunnerState, LineupPlayerState, TeamLineupState - DefensiveDecision and OffensiveDecision models - Full Pydantic v2 validation with field validators - app/core/state_manager.py (296 lines) - In-memory state management with O(1) lookups - State recovery from database - Idle game eviction mechanism - Statistics tracking - app/database/operations.py (362 lines) - Async PostgreSQL operations - Game, lineup, and play persistence - Complete state loading for recovery - GameSession WebSocket state tracking ### Tests (4 files, 1,963 lines, 115 tests) - tests/unit/models/test_game_models.py (60 tests, ALL PASSING) - tests/unit/core/test_state_manager.py (26 tests, ALL PASSING) - tests/integration/database/test_operations.py (21 tests) - tests/integration/test_state_persistence.py (8 tests) - pytest.ini (async test configuration) ### Documentation (6 files) - backend/CLAUDE.md (updated with Week 4 patterns) - .claude/implementation/02-week4-state-management.md (marked complete) - .claude/status-2025-10-22-0113.md (planning session summary) - .claude/status-2025-10-22-1147.md (implementation session summary) - .claude/implementation/player-data-catalog.md (player data reference) - Week 5 & 6 plans created ## Key Features - Hybrid state: in-memory (fast) + PostgreSQL (persistent) - O(1) state access via dictionary lookups - Async database writes (non-blocking) - Complete state recovery from database - Pydantic validation on all models - Helper methods for common game operations - Idle game eviction with configurable timeout - 86 unit tests passing (100%) ## Performance - State access: O(1) via UUID lookup - Memory per game: ~1KB (just state) - Target response time: <500ms ✅ - Database writes: <100ms (async) ✅ ## Testing - Unit tests: 86/86 passing (100%) - Integration tests: 29 written - Test configuration: pytest.ini created - Fixed Pydantic v2 config deprecation - Fixed pytest-asyncio configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
d8a43faa2e |
CLAUDE: Complete Phase 1 - Frontend Infrastructure Setup
Initialize both Nuxt 3 frontends (SBA and PD) with full configuration: Frontend Setup: - Initialized Nuxt 3 projects for both leagues (SBA and PD) - Installed dependencies: Tailwind CSS, Pinia, Socket.io-client, Axios - Configured league-specific settings in nuxt.config.ts - Created WebSocket plugins for real-time communication - Set up TypeScript with strict mode and type checking - Configured Tailwind CSS for styling Backend Updates: - Updated database models documentation in backend/CLAUDE.md - Enhanced db_models.py with additional relationship patterns Documentation: - Updated Phase 1 completion checklist (12/12 items - 100% complete) - Marked all infrastructure objectives as complete Running Services: - Backend (FastAPI + Socket.io): http://localhost:8000 - Frontend SBA: http://localhost:3000 - Frontend PD: http://localhost:3001 - Redis: port 6379 - PostgreSQL: Connected to remote server Phase 1 is now complete. Ready to proceed to Phase 2 (Game Engine Core). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
fc7f53adf3 |
CLAUDE: Complete Phase 1 backend infrastructure setup
Implemented full FastAPI backend with WebSocket support, database models, and comprehensive documentation for the Paper Dynasty game engine. Backend Implementation: - FastAPI application with Socket.io WebSocket server - SQLAlchemy async database models (Game, Play, Lineup, GameSession) - PostgreSQL connection to dev server (10.10.0.42:5432) - Connection manager for WebSocket lifecycle - JWT authentication utilities - Health check and stub API endpoints - Rotating file logger with Pendulum datetime handling - Redis via Docker Compose for caching Technical Details: - Python 3.13 with updated package versions - Pendulum 3.0 for all datetime operations - Greenlet for SQLAlchemy async support - Fixed SQLAlchemy reserved column names (metadata -> *_metadata) - Pydantic Settings with JSON array format for lists - Docker Compose V2 commands Documentation: - Updated backend/CLAUDE.md with environment-specific details - Created .claude/ENVIRONMENT.md for gotchas and quirks - Created QUICKSTART.md for developer onboarding - Documented all critical learnings and troubleshooting steps Database: - Tables created: games, plays, lineups, game_sessions - All indexes and foreign keys configured - Successfully tested connection and health checks Verified: - Server starts at http://localhost:8000 - Health endpoints responding - Database connection working - WebSocket infrastructure functional - Hot-reload working 🎯 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |