paper-dynasty-gameplay-webapp/app/models
Cal Corum 7fd9079425 CLAUDE: Improve AI Service test coverage from 60% to 72% with comprehensive integration tests
Added targeted integration tests to cover previously uncovered conditional branches
and edge cases in AI decision-making logic:

- test_ai_service_focused_coverage.py: 11 tests for key missing branches
  * Steal opportunity conditions (lines 91, 93, 98-99, 108)
  * Steal to third/home scenarios (lines 129, 157, 161)
  * Defensive alignment logic (lines 438, 480)
  * Tag decision branches (lines 204, 253)

- test_ai_service_final_coverage.py: 10 tests for remaining gaps
  * Complex steal conditions (lines 95, 118-119, 132, 136-137, 141)
  * Late inning steal logic (lines 159, 163)
  * Uncapped advance bounds checking (lines 382-388)
  * Complex defensive scenarios (lines 440-449)

- test_ai_service_coverage.py: Comprehensive coverage tests (unused due to complexity)

Fixed:
- Player model relationship syntax (removed unsupported cascade_delete parameter)
- Existing test assertion in test_ai_service_simple.py for steal to home scenario

Coverage improvement: 369 statements, 147→105 missed lines (60%→72% coverage)
All 49 AI Service tests now pass with comprehensive integration testing.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-29 21:28:43 -05:00
..
__init__.py CLAUDE: Complete Player model migration with service layer and integration test infrastructure 2025-09-29 16:20:29 -05:00
ai_responses.py CLAUDE: Achieve 100% test pass rate with comprehensive AI service testing 2025-09-28 17:55:34 -05:00
cardset.py CLAUDE: Complete Player model migration with service layer and integration test infrastructure 2025-09-29 16:20:29 -05:00
manager_ai.py CLAUDE: Achieve 100% test pass rate with comprehensive AI service testing 2025-09-28 17:55:34 -05:00
player.py CLAUDE: Improve AI Service test coverage from 60% to 72% with comprehensive integration tests 2025-09-29 21:28:43 -05:00
position_rating.py CLAUDE: Complete Player model migration with service layer and integration test infrastructure 2025-09-29 16:20:29 -05:00
README.md CLAUDE: Achieve 100% test pass rate with comprehensive AI service testing 2025-09-28 17:55:34 -05:00
team.py CLAUDE: Achieve 100% test pass rate with comprehensive AI service testing 2025-09-28 17:55:34 -05:00

Models Directory

This directory contains pure data models for the Paper Dynasty web app, migrated from the Discord app following the Model/Service Architecture pattern.

Architecture Principle

Models = Pure Data | Services = Business Logic

  • Models: Field definitions, relationships, basic validators only
  • Services: Complex logic, UI formatting, game management, AI decisions

Migration Status

Completed Models

Model Status Description Business Logic Extracted
ManagerAi Complete AI configuration data AIService (9 methods)
Cardset Complete Card set metadata None (pure data)

🚧 In Progress

Model Status Description Business Logic to Extract
Team 📋 Next Team identity data UIService (embed property)
Player 📋 Planned Player metadata UIService (Discord markdown)

📋 Future Phases

  • Phase 3: Game structure (Game, Play models)
  • Phase 4: Card and rating models
  • Phase 5: Web-specific models (sessions, preferences)

Model Patterns

Pure Data Model Structure

# Base model for validation and field definitions
class ModelBase(SQLModel):
    id: int | None = Field(default=None, primary_key=True)
    name: str = Field(index=True, description="Field description")

    @field_validator('name')
    @classmethod
    def validate_name(cls, v: str) -> str:
        # Basic validation only
        if not v or not v.strip():
            raise ValueError("Name cannot be empty")
        return v

# Table model for database operations
class Model(ModelBase, table=True):
    # relationships: List["RelatedModel"] = Relationship(...)
    pass

What STAYS in Models

Field definitions and types

name: str = Field(index=True)
ranked_legal: bool = Field(default=False)

Database relationships

players: List["Player"] = Relationship(back_populates="cardset")

Basic field validation

@field_validator('name')
def validate_name_not_empty(cls, v: str) -> str:
    if not v.strip():
        raise ValueError("Name cannot be empty")
    return v

What MOVES to Services

Complex business logic

# BEFORE (in model)
def check_steal_opportunity(self, game, to_base):
    # Complex AI decision logic...

# AFTER (in service)
def check_steal_opportunity(self, manager_ai, game, to_base):
    # Same logic but in AIService

UI formatting

# BEFORE (in model)
@property
def embed(self) -> discord.Embed:
    # Discord-specific formatting...

# AFTER (in service)
def format_team_display(self, team) -> dict:
    # Platform-agnostic formatting

Game mechanics

# BEFORE (in model)
def initialize_play(self, session):
    # Complex game setup logic...

# AFTER (in service)
def initialize_game(self, game_id) -> Play:
    # Same logic but in GameService

Testing Strategy

All models use the factory pattern with transaction rollback:

# test_model.py
def test_model_creation(db_session):
    model = ModelFactory.create(db_session, field="value")
    assert model.field == "value"
    # Automatic rollback ensures isolation

See tests/README.md for complete testing documentation.

File Organization

models/
├── __init__.py              # Export all models
├── manager_ai.py           # ✅ AI configuration (complete)
├── cardset.py              # ✅ Card set metadata (complete)
├── team.py                 # 🚧 Team identity (next)
├── player.py               # 📋 Player metadata (planned)
├── game.py                 # 📋 Game structure (planned)
├── play.py                 # 📋 Gameplay state (planned)
└── ai_responses.py         # AI decision response models

Migration Guidelines

When migrating a model from ../discord-app/:

1. Analyze Original Model

# Find the model in Discord app
grep -r "class ModelName" ../discord-app/

2. Separate Data from Logic

  • Keep: Field definitions, relationships, basic validation
  • Extract: Methods, computed properties, complex logic

3. Create Pure Data Model

class ModelBase(SQLModel):
    # Only field definitions and basic validation

class Model(ModelBase, table=True):
    # Only relationships

4. Extract Business Logic

class ModelService(BaseService):
    def extracted_method(self, model_instance, params):
        # Migrated business logic

5. Create Comprehensive Tests

# Validation tests (no database)
def test_model_validation():
    model = ModelFactory.build(invalid_field="bad")
    # Test validation

# Database tests (with rollback)
def test_model_persistence(db_session):
    model = ModelFactory.create(db_session)
    # Test database operations

6. Update Migration Plan

  • Mark model as complete in .claude/model-migration-plan.md
  • Update this README with new model status

Dependencies

Models depend on:

  • sqlmodel - Database ORM and validation
  • pydantic - Field validation and serialization
  • sqlalchemy - Advanced database features

Models should NOT depend on:

  • discord.py - Platform-specific library
  • fastapi - Web framework
  • Service classes - Business logic layer

Best Practices

DO:

  • Keep models as simple data containers
  • Use descriptive field documentation
  • Add basic validation for data integrity
  • Follow naming conventions from original models
  • Create comprehensive factory-based tests

DON'T:

  • Add business logic methods to models
  • Include platform-specific dependencies
  • Create computed properties with complex logic
  • Hard-code values that belong in services
  • Skip validation or tests

Future Considerations

As we complete the migration:

  1. Web-specific models will be added for session management
  2. Performance optimization may require relationship tuning
  3. Database migrations will be managed via Alembic
  4. API serialization will use Pydantic's serialization features

The goal is to have a clean, testable, platform-agnostic data layer that can support web, mobile, and future interfaces.