Add forced action handling, turn boundary detection, and DB persistence:
- Check for pending forced actions before allowing regular actions
- Only specified player can act during forced action (except resign)
- Only specified action type allowed during forced action
- Detect turn boundaries (turn number OR current player change)
- Persist to Postgres at turn boundaries for durability
- Include pending_forced_action in GameActionResult for client
New exceptions: ForcedActionRequiredError
Tests: 11 new tests covering forced actions, turn boundaries, and
pending action reporting. Total 47 tests for GameService.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Architectural refactor to eliminate circular imports and establish clean
module boundaries:
- Move enums from app/core/models/enums.py to app/core/enums.py
(foundational module with zero dependencies)
- Update all imports across 30 files to use new enum location
- Set up clean export structure:
- app.core.enums: canonical source for all enums
- app.core: convenience exports for full public API
- app.core.models: exports models only (not enums)
- Add module exports to app/core/__init__.py and app/core/effects/__init__.py
- Remove circular import workarounds from game_state.py
This enables app.core.models to export GameState without circular import
issues, since enums no longer depend on the models package.
All 826 tests passing.
- Implement rules_validator.py with config-driven action validation for all 11 action types
- Implement win_conditions.py with point/prize-based, knockout, deck-out, turn limit, and timeout checks
- Add ForcedAction model to GameState for blocking actions (e.g., select new active after KO)
- Add ActiveConfig with max_active setting for future double-battle support
- Add TrainerConfig.stadium_same_name_replace option
- Add DeckConfig.starting_hand_size option
- Rename from_energy_deck to from_energy_zone for consistency
- Fix unreachable code bug in GameState.get_opponent_id()
- Add 16 coverage gap tests for edge cases (card registry corruption, forced actions, etc.)
- 584 tests passing at 97% coverage
Completes HIGH-005, HIGH-006, TEST-009, TEST-010 from PROJECT_PLAN.json
- Add CardDefinition and CardInstance models for card templates and in-game state
- Add Attack, Ability, and WeaknessResistance models for Pokemon card components
- Add 11 action types as discriminated union (PlayPokemon, Evolve, Attack, etc.)
- Split PokemonStage (BASIC, STAGE_1, STAGE_2) from PokemonVariant (NORMAL, EX, GX, V, VMAX, VSTAR)
- Stage determines evolution mechanics, variant determines knockout points
- Update PrizeConfig to use variant for knockout point calculation
- VSTAR and VMAX both worth 3 points; EX, GX, V worth 2 points; NORMAL worth 1 point
Tests: 204 passing, all linting clean
- Create core module structure with models and effects subdirectories
- Add enums module with CardType, EnergyType, TurnPhase, StatusCondition, etc.
- Add RulesConfig with Mantimon TCG defaults (40-card deck, 4 points to win)
- Add RandomProvider protocol with SeededRandom (testing) and SecureRandom (production)
- Include comprehensive tests for all modules (97 tests passing)
Defaults reflect GAME_RULES.md: Pokemon Pocket-style energy deck,
first turn can attack but not attach energy, 30-turn limit enabled.