214 lines
7.1 KiB
Markdown
214 lines
7.1 KiB
Markdown
# MTG Card Interaction Pipeline - Code Review
|
|
|
|
## Overview
|
|
|
|
The interaction pipeline consists of four main modules:
|
|
1. `card_profile_extractor.py` - Extracts structured profiles from MTGJSON data
|
|
2. `interaction_determinator.py` - Determines interactions between card pairs
|
|
3. `interaction_recommender.py` - Generates recommendations based on interactions
|
|
4. `interaction_pipeline.py` - Orchestrates the full pipeline
|
|
|
|
## Issues Found
|
|
|
|
### 1. Import Inconsistency (Critical)
|
|
**File**: `interaction_pipeline.py`
|
|
**Issue**: Complex import for `sessionmaker`
|
|
```python
|
|
self.SessionLocal = __import__('sqlalchemy.orm', fromlist=['sessionmaker']).sessionmaker(bind=self.engine)
|
|
```
|
|
**Fix**: Use direct import at module level:
|
|
```python
|
|
from sqlalchemy.orm import sessionmaker
|
|
# ...
|
|
self.SessionLocal = sessionmaker(bind=self.engine)
|
|
```
|
|
|
|
### 2. Type Hints Inconsistency (Medium)
|
|
**File**: `interaction_pipeline.py`
|
|
**Issue**: Inconsistent type hints
|
|
```python
|
|
def extract_profiles(self, cards: List[Dict]) -> List: # Missing type parameter
|
|
def determine_interactions(self, profiles) -> dict: # Missing parameter type
|
|
```
|
|
**Fix**: Add proper type hints:
|
|
```python
|
|
def extract_profiles(self, cards: List[Dict]) -> List[CardProfile]:
|
|
def determine_interactions(self, profiles: List[CardProfile]) -> dict:
|
|
```
|
|
|
|
### 3. Complex Conditional Logic (High)
|
|
**File**: `interaction_pipeline.py`
|
|
**Issue**: Nested ternary operators for synergy_type and counter_type determination
|
|
```python
|
|
"synergy_type": "archetype" if interaction.metadata and interaction.metadata.get('common_archetypes') else
|
|
"mechanic" if interaction.metadata and interaction.metadata.get('mechanics') else
|
|
"mana" if interaction.metadata and interaction.metadata.get('colors') else
|
|
"combo" if interaction.metadata and interaction.metadata.get('card_a_targets') else
|
|
"support",
|
|
```
|
|
**Fix**: Extract to helper methods or use lookup dictionaries
|
|
|
|
### 4. Missing Validation (Medium)
|
|
**File**: `interaction_pipeline.py`
|
|
**Issue**: No validation for empty card lists or invalid data
|
|
**Fix**: Add validation at the start of methods
|
|
|
|
### 5. Evolution Type Mapping (High)
|
|
**File**: `interaction_pipeline.py`
|
|
**Issue**: Using `interaction.interaction_type` which is 'evolution' for all evolutions
|
|
**Fix**: Map to specific evolution types based on metadata
|
|
|
|
## Recommended Fixes
|
|
|
|
### Fix 1: Import Structure
|
|
```python
|
|
# At top of file
|
|
from sqlalchemy import create_engine, text
|
|
from sqlalchemy.orm import sessionmaker
|
|
|
|
# In __init__
|
|
self.SessionLocal = sessionmaker(bind=self.engine)
|
|
```
|
|
|
|
### Fix 2: Type Hints
|
|
```python
|
|
def extract_profiles(self, cards: List[Dict]) -> List[CardProfile]:
|
|
return self.profile_extractor.extract_profiles_batch(cards)
|
|
|
|
def determine_interactions(self, profiles: List[CardProfile]) -> dict:
|
|
return self.determinator.determine_all_interactions(profiles)
|
|
```
|
|
|
|
### Fix 3: Helper Methods for Type Determination
|
|
```python
|
|
def _determine_synergy_type(self, interaction) -> str:
|
|
"""Determine synergy type from interaction metadata."""
|
|
metadata = interaction.metadata or {}
|
|
|
|
if 'common_archetypes' in metadata:
|
|
return 'archetype'
|
|
elif 'mechanics' in metadata:
|
|
return 'mechanic'
|
|
elif 'colors' in metadata:
|
|
return 'mana'
|
|
elif 'card_a_targets' in metadata:
|
|
return 'combo'
|
|
else:
|
|
return 'support'
|
|
|
|
def _determine_counter_type(self, interaction) -> str:
|
|
"""Determine counter type from interaction metadata."""
|
|
metadata = interaction.metadata or {}
|
|
|
|
if 'colors_a' in metadata:
|
|
return 'color'
|
|
elif 'power_a' in metadata:
|
|
return 'stats'
|
|
else:
|
|
return 'keyword'
|
|
|
|
def _determine_evolution_type(self, interaction) -> str:
|
|
"""Determine evolution type from interaction metadata."""
|
|
metadata = interaction.metadata or {}
|
|
|
|
if 'card_name' in metadata:
|
|
return 'reprint'
|
|
else:
|
|
return 'evolution'
|
|
```
|
|
|
|
### Fix 4: Add Validation
|
|
```python
|
|
def run_initial_load(self, set_code: Optional[str] = None):
|
|
"""Run initial load with validation."""
|
|
if not set_code:
|
|
logger.info("No set code provided, loading all cards")
|
|
|
|
all_cards = self.load_cards_from_db(set_code)
|
|
|
|
if not all_cards:
|
|
logger.warning("No cards found in database")
|
|
return
|
|
|
|
# Continue with processing...
|
|
```
|
|
|
|
## Accuracy Review
|
|
|
|
### Profile Extraction
|
|
✅ **Correct**: Color extraction from mana cost
|
|
✅ **Correct**: Mechanic extraction using regex patterns
|
|
✅ **Correct**: Archetype extraction from subtypes
|
|
✅ **Correct**: Target extraction from oracle text
|
|
✅ **Correct**: Trigger and effect extraction
|
|
✅ **Correct**: Theme extraction based on characteristics
|
|
|
|
### Interaction Determination
|
|
✅ **Correct**: Archetype synergy detection
|
|
✅ **Correct**: Mana synergy detection
|
|
✅ **Correct**: Mechanic synergy detection (haste+trample, lifelink+combat)
|
|
✅ **Correct**: Combo synergy detection (targets + triggers)
|
|
✅ **Correct**: Support synergy detection
|
|
✅ **Correct**: Counter detection (color, stats, keywords)
|
|
✅ **Correct**: Evolution detection (reprints)
|
|
|
|
### Database Schema
|
|
✅ **Correct**: Synergies table with proper constraints
|
|
✅ **Correct**: Counters table with proper constraints
|
|
✅ **Correct**: Evolutions table with proper constraints
|
|
✅ **Correct**: Statistics table with proper aggregations
|
|
✅ **Correct**: Foreign key relationships
|
|
✅ **Correct**: Unique constraints to prevent duplicates
|
|
|
|
## Consistency Issues
|
|
|
|
### 1. File Organization
|
|
- All files in `/home/wall-o/projects/mtgonline/backend/scripts/`
|
|
- No clear separation between core logic and pipeline
|
|
- **Recommendation**: Keep as is for simplicity
|
|
|
|
### 2. Naming Conventions
|
|
- **Good**: Consistent use of snake_case for methods
|
|
- **Good**: Consistent use of CamelCase for classes
|
|
- **Issue**: Mixed use of `set_code` parameter naming
|
|
- **Recommendation**: Standardize on `set_code`
|
|
|
|
### 3. Error Handling
|
|
- **Good**: Try/finally blocks for database connections
|
|
- **Issue**: No specific exception handling for database errors
|
|
- **Recommendation**: Add specific exception types
|
|
|
|
### 4. Logging
|
|
- **Good**: Consistent logging format
|
|
- **Good**: Appropriate log levels (INFO, WARNING, ERROR)
|
|
- **Issue**: Missing DEBUG logging for development
|
|
- **Recommendation**: Add DEBUG level logging
|
|
|
|
## Summary
|
|
|
|
### Critical Issues (Must Fix)
|
|
1. ❌ Import structure for sessionmaker
|
|
2. ❌ Complex conditional logic for type determination
|
|
|
|
### High Priority Issues (Should Fix)
|
|
3. ❌ Missing type hints
|
|
4. ❌ Evolution type mapping
|
|
5. ❌ Missing validation
|
|
|
|
### Medium Priority Issues (Nice to Have)
|
|
6. ⚠️ Add specific exception handling
|
|
7. ⚠️ Add DEBUG logging
|
|
8. ⚠️ Standardize parameter naming
|
|
|
|
### Low Priority Issues (Can Defer)
|
|
9. ✅ All core logic is accurate and correct
|
|
10. ✅ Database schema is well-designed
|
|
11. ✅ Interaction determination logic is sound
|
|
|
|
## Next Steps
|
|
|
|
1. **Fix Critical Issues**: Update import structure and simplify conditional logic
|
|
2. **Fix High Priority**: Add proper type hints and validation
|
|
3. **Test**: Run pipeline with sample data to verify functionality
|
|
4. **Document**: Add docstrings and inline comments for complex logic
|