mantimon-tcg/backend/PROJECT_PLAN.json
Cal Corum 3e82280efb Add game engine foundation: enums, config, and RNG modules
- 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.
2026-01-24 22:14:45 -06:00

653 lines
29 KiB
JSON

{
"meta": {
"version": "1.0.0",
"created": "2026-01-24",
"lastUpdated": "2026-01-24",
"planType": "feature",
"projectName": "Mantimon TCG - Backend Game Engine",
"description": "Core game engine scaffolding for a highly configurable Pokemon TCG-inspired card game. The engine must support campaign mode with fixed rules and free play mode with user-configurable rules.",
"totalEstimatedHours": 48,
"totalTasks": 32,
"completedTasks": 0
},
"categories": {
"critical": "Foundation components that block all other work",
"high": "Core engine functionality required for basic gameplay",
"medium": "Important features for complete gameplay experience",
"low": "Polish, optimization, and nice-to-have features",
"feature": "New capabilities beyond MVP"
},
"architectureDecisions": {
"configurability": "All game rules driven by RulesConfig - defaults for campaign, user-adjustable for free play",
"rngHandling": "RandomProvider protocol with SeededRandom (tests/replays) and SecureRandom (production PvP)",
"cardRegistry": "Hybrid - definitions loaded from DB via CardService, embedded in GameState at game creation for self-contained gameplay",
"cardModels": "Separate CardDefinition (immutable template) from CardInstance (mutable in-game state)",
"actionModeling": "Union types for type safety",
"asyncSupport": "Async throughout for WebSocket compatibility"
},
"directoryStructure": {
"core": "backend/app/core/",
"models": "backend/app/core/models/",
"effects": "backend/app/core/effects/",
"tests": "backend/tests/core/"
},
"tasks": [
{
"id": "CRIT-001",
"name": "Create core module structure",
"description": "Set up the directory structure and __init__.py files for the core game engine module hierarchy",
"category": "critical",
"priority": 1,
"completed": false,
"tested": false,
"dependencies": [],
"files": [
{"path": "app/core/__init__.py", "issue": "File does not exist"},
{"path": "app/core/models/__init__.py", "issue": "File does not exist"},
{"path": "app/core/effects/__init__.py", "issue": "File does not exist"},
{"path": "tests/core/__init__.py", "issue": "File does not exist"},
{"path": "tests/core/test_models/__init__.py", "issue": "File does not exist"},
{"path": "tests/core/test_effects/__init__.py", "issue": "File does not exist"}
],
"suggestedFix": "Create all directories and empty __init__.py files with appropriate module docstrings",
"estimatedHours": 0.5,
"notes": "Foundation task - must be completed first"
},
{
"id": "CRIT-002",
"name": "Create enums module",
"description": "Define all enumeration types used throughout the game engine: CardType, EnergyType, PokemonStage, TurnPhase, StatusCondition, TrainerType, ActionType",
"category": "critical",
"priority": 2,
"completed": false,
"tested": false,
"dependencies": ["CRIT-001"],
"files": [
{"path": "app/core/models/enums.py", "issue": "File does not exist"}
],
"suggestedFix": "Create StrEnum classes for each enumeration type. Use StrEnum for JSON serialization compatibility.",
"estimatedHours": 1,
"notes": "All other modules depend on these enums. Consider future extensibility for custom energy types."
},
{
"id": "TEST-001",
"name": "Create enums tests",
"description": "Test that all enums serialize correctly to JSON, have expected values, and can be used in Pydantic models",
"category": "high",
"priority": 3,
"completed": false,
"tested": false,
"dependencies": ["CRIT-002"],
"files": [
{"path": "tests/core/test_models/test_enums.py", "issue": "File does not exist"}
],
"suggestedFix": "Test each enum: value consistency, JSON round-trip, membership checks",
"estimatedHours": 0.5,
"notes": "Simple tests but establish testing patterns for the project"
},
{
"id": "CRIT-003",
"name": "Create RulesConfig module",
"description": "Define the master configuration system for all game rules with sensible defaults. Includes: DeckConfig, BenchConfig, EnergyConfig, PrizeConfig, FirstTurnConfig, WinConditionsConfig, StatusConfig, TrainerConfig",
"category": "critical",
"priority": 4,
"completed": false,
"tested": false,
"dependencies": ["CRIT-002"],
"files": [
{"path": "app/core/config.py", "issue": "File does not exist"}
],
"suggestedFix": "Create nested Pydantic BaseModel classes with Field defaults. Use Field(default_factory=...) for mutable defaults.",
"estimatedHours": 2,
"notes": "This is the heart of the configurability requirement. Defaults should approximate standard Pokemon TCG rules. Document each config option thoroughly."
},
{
"id": "TEST-002",
"name": "Create RulesConfig tests",
"description": "Test that RulesConfig has sensible defaults, custom values override correctly, and serialization round-trips work",
"category": "high",
"priority": 5,
"completed": false,
"tested": false,
"dependencies": ["CRIT-003"],
"files": [
{"path": "tests/core/test_config.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: default instantiation, partial overrides, full JSON round-trip, validation of invalid values",
"estimatedHours": 1,
"notes": "Important to verify all defaults match expected standard rules"
},
{
"id": "CRIT-004",
"name": "Create RandomProvider module",
"description": "Implement the RandomProvider protocol with SeededRandom (for testing/replays) and SecureRandom (for production PvP) implementations",
"category": "critical",
"priority": 6,
"completed": false,
"tested": false,
"dependencies": ["CRIT-001"],
"files": [
{"path": "app/core/rng.py", "issue": "File does not exist"}
],
"suggestedFix": "Create Protocol class with random(), randint(), choice(), shuffle() methods. Implement SeededRandom using random.Random with seed, SecureRandom using secrets module.",
"estimatedHours": 1.5,
"notes": "Critical for testability. SeededRandom enables deterministic tests for coin flips and shuffles."
},
{
"id": "TEST-003",
"name": "Create RandomProvider tests",
"description": "Test that SeededRandom produces deterministic results and SecureRandom produces varied results",
"category": "high",
"priority": 7,
"completed": false,
"tested": false,
"dependencies": ["CRIT-004"],
"files": [
{"path": "tests/core/test_rng.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: SeededRandom with same seed produces identical sequences, SecureRandom produces different values across calls (statistical test)",
"estimatedHours": 1,
"notes": "SeededRandom tests should be fully deterministic. SecureRandom tests should verify randomness."
},
{
"id": "HIGH-001",
"name": "Create CardDefinition and CardInstance models",
"description": "Define the card template (CardDefinition) and in-game card state (CardInstance) models. Includes Attack, Ability sub-models.",
"category": "high",
"priority": 8,
"completed": false,
"tested": false,
"dependencies": ["CRIT-002"],
"files": [
{"path": "app/core/models/card.py", "issue": "File does not exist"}
],
"suggestedFix": "CardDefinition: immutable template with id, name, card_type, stage, hp, attacks, abilities, weakness, resistance, retreat_cost. CardInstance: mutable state with instance_id, definition_id, damage, attached_energy, status_conditions, turn_played.",
"estimatedHours": 2,
"notes": "CardInstance should only store mutable state. All static card data comes from CardDefinition lookup."
},
{
"id": "TEST-004",
"name": "Create card model tests",
"description": "Test CardDefinition and CardInstance creation, validation, and serialization",
"category": "high",
"priority": 9,
"completed": false,
"tested": false,
"dependencies": ["HIGH-001"],
"files": [
{"path": "tests/core/test_models/test_card.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: Pokemon card creation with attacks, Trainer card creation, Energy card creation, CardInstance damage tracking, energy attachment, status conditions",
"estimatedHours": 1.5,
"notes": "Create sample card fixtures for reuse in other tests"
},
{
"id": "HIGH-002",
"name": "Create Action union types",
"description": "Define all player action types as Pydantic models with Literal type discriminators: PlayPokemonAction, EvolvePokemonAction, AttachEnergyAction, PlayTrainerAction, UseAbilityAction, AttackAction, RetreatAction, PassAction",
"category": "high",
"priority": 10,
"completed": false,
"tested": false,
"dependencies": ["CRIT-002"],
"files": [
{"path": "app/core/models/actions.py", "issue": "File does not exist"}
],
"suggestedFix": "Each action model has a 'type' field with Literal value for discrimination. Create Action = Union[...] type alias for all actions.",
"estimatedHours": 1.5,
"notes": "Union type enables type-safe action handling. Each action should have all parameters needed for validation and execution."
},
{
"id": "TEST-005",
"name": "Create action model tests",
"description": "Test that action union types discriminate correctly and serialize/deserialize properly",
"category": "high",
"priority": 11,
"completed": false,
"tested": false,
"dependencies": ["HIGH-002"],
"files": [
{"path": "tests/core/test_models/test_actions.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: each action type creates correctly, JSON round-trip works, discriminated union parses correct type",
"estimatedHours": 1,
"notes": "Test that parsing JSON into Action union correctly identifies the specific action type"
},
{
"id": "HIGH-003",
"name": "Create GameState, PlayerState, and Zone models",
"description": "Define the complete game state model hierarchy: Zone (card collection with operations), PlayerState (all player zones and turn state), GameState (full game including card_registry, rules, players, turn tracking)",
"category": "high",
"priority": 12,
"completed": false,
"tested": false,
"dependencies": ["CRIT-003", "HIGH-001"],
"files": [
{"path": "app/core/models/game_state.py", "issue": "File does not exist"}
],
"suggestedFix": "Zone: list of CardInstance with add/remove/shuffle/draw methods. PlayerState: deck, hand, active, bench, prizes, discard zones plus turn state flags. GameState: game_id, rules, card_registry, players dict, turn tracking, winner.",
"estimatedHours": 3,
"notes": "GameState.card_registry holds all CardDefinitions used in this game. Zone operations need RandomProvider for shuffle."
},
{
"id": "TEST-006",
"name": "Create game state model tests",
"description": "Test Zone operations, PlayerState initialization and turn resets, GameState properties and player access",
"category": "high",
"priority": 13,
"completed": false,
"tested": false,
"dependencies": ["HIGH-003"],
"files": [
{"path": "tests/core/test_models/test_game_state.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: Zone add/remove/shuffle/draw, PlayerState turn state resets, GameState current_player property, GameState is_first_turn logic",
"estimatedHours": 2,
"notes": "Use SeededRandom for deterministic shuffle tests"
},
{
"id": "HIGH-004",
"name": "Create test fixtures (conftest.py)",
"description": "Create shared pytest fixtures for sample cards, game states, and seeded RNG instances",
"category": "high",
"priority": 14,
"completed": false,
"tested": false,
"dependencies": ["HIGH-001", "HIGH-003", "CRIT-004"],
"files": [
{"path": "tests/core/conftest.py", "issue": "File does not exist"}
],
"suggestedFix": "Create fixtures: sample_pokemon_card, sample_trainer_card, sample_energy_card, sample_deck, empty_game_state, mid_game_state, seeded_rng",
"estimatedHours": 1.5,
"notes": "Fixtures should be composable and reusable across all test modules"
},
{
"id": "MED-001",
"name": "Create EffectContext and base types",
"description": "Define the context object passed to effect handlers and the EffectResult return type",
"category": "medium",
"priority": 15,
"completed": false,
"tested": false,
"dependencies": ["HIGH-003"],
"files": [
{"path": "app/core/effects/base.py", "issue": "File does not exist"}
],
"suggestedFix": "EffectContext: game state, source player/card, target player/card, params dict, rng provider. EffectResult: success bool, message, state changes list for logging.",
"estimatedHours": 1,
"notes": "EffectContext should provide helper methods for common operations (get card by id, get opponent, etc.)"
},
{
"id": "MED-002",
"name": "Create effect handler registry",
"description": "Implement the effect handler registry with decorator for registering handlers and lookup function for resolving effects",
"category": "medium",
"priority": 16,
"completed": false,
"tested": false,
"dependencies": ["MED-001"],
"files": [
{"path": "app/core/effects/registry.py", "issue": "File does not exist"}
],
"suggestedFix": "Global EFFECT_REGISTRY dict. @effect_handler(name) decorator adds function to registry. resolve_effect(effect_id, context) looks up and calls handler.",
"estimatedHours": 1,
"notes": "Consider async handlers for effects that might need I/O in the future"
},
{
"id": "TEST-007",
"name": "Create effect registry tests",
"description": "Test that effect handlers register correctly and resolve_effect calls the right handler",
"category": "medium",
"priority": 17,
"completed": false,
"tested": false,
"dependencies": ["MED-002"],
"files": [
{"path": "tests/core/test_effects/test_registry.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: decorator registers handler, resolve_effect calls correct handler, unknown effect_id handled gracefully",
"estimatedHours": 1,
"notes": "Use mock handlers for testing registration"
},
{
"id": "MED-003",
"name": "Create built-in effect handlers",
"description": "Implement common effect handlers: deal_damage, heal, draw_cards, discard_cards, apply_status, remove_status, coin_flip, discard_energy, search_deck",
"category": "medium",
"priority": 18,
"completed": false,
"tested": false,
"dependencies": ["MED-002"],
"files": [
{"path": "app/core/effects/handlers.py", "issue": "File does not exist"}
],
"suggestedFix": "Each handler is an async function decorated with @effect_handler. Use context.params for effect-specific parameters. Return EffectResult with success/failure.",
"estimatedHours": 3,
"notes": "coin_flip handler should use context.rng for testability. Effects should mutate game state in place."
},
{
"id": "TEST-008",
"name": "Create effect handler tests",
"description": "Test each built-in effect handler with various scenarios",
"category": "medium",
"priority": 19,
"completed": false,
"tested": false,
"dependencies": ["MED-003", "HIGH-004"],
"files": [
{"path": "tests/core/test_effects/test_handlers.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: deal_damage reduces HP, heal restores HP up to max, draw_cards moves from deck to hand, apply_status adds condition, coin_flip with seeded RNG",
"estimatedHours": 2,
"notes": "Use seeded RNG fixtures for deterministic coin flip tests"
},
{
"id": "HIGH-005",
"name": "Create rules validator",
"description": "Implement config-driven action validation: check turn, phase, card ownership, action legality based on RulesConfig",
"category": "high",
"priority": 20,
"completed": false,
"tested": false,
"dependencies": ["HIGH-002", "HIGH-003", "CRIT-003"],
"files": [
{"path": "app/core/rules_validator.py", "issue": "File does not exist"}
],
"suggestedFix": "ValidationResult model with valid bool and reason string. validate_action(game, player_id, action) checks: is it player's turn, is phase correct, does player have the card, is action legal per rules. Separate validator functions per action type.",
"estimatedHours": 4,
"notes": "Most complex validation module. Must check all rule configurations (energy attachments per turn, supporter limit, bench size, etc.)"
},
{
"id": "TEST-009",
"name": "Create rules validator tests",
"description": "Test action validation for each action type with valid and invalid scenarios",
"category": "high",
"priority": 21,
"completed": false,
"tested": false,
"dependencies": ["HIGH-005", "HIGH-004"],
"files": [
{"path": "tests/core/test_rules_validator.py", "issue": "File does not exist"}
],
"suggestedFix": "Test per action type: valid action passes, wrong turn fails, wrong phase fails, card not owned fails, rule limit exceeded fails. Test with custom RulesConfig to verify config-driven behavior.",
"estimatedHours": 3,
"notes": "Critical tests - security depends on proper validation"
},
{
"id": "HIGH-006",
"name": "Create win conditions checker",
"description": "Implement config-driven win condition checking: all prizes taken, no Pokemon in play, cannot draw",
"category": "high",
"priority": 22,
"completed": false,
"tested": false,
"dependencies": ["HIGH-003", "CRIT-003"],
"files": [
{"path": "app/core/win_conditions.py", "issue": "File does not exist"}
],
"suggestedFix": "WinResult model with winner player_id and reason string. check_win_conditions(game) checks each enabled condition from rules config and returns WinResult if any are met.",
"estimatedHours": 1.5,
"notes": "Check each condition independently based on game.rules.win_conditions flags"
},
{
"id": "TEST-010",
"name": "Create win conditions tests",
"description": "Test each win condition triggers correctly and respects config flags",
"category": "high",
"priority": 23,
"completed": false,
"tested": false,
"dependencies": ["HIGH-006", "HIGH-004"],
"files": [
{"path": "tests/core/test_win_conditions.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: all prizes taken triggers win, last Pokemon knocked out triggers win, empty deck triggers win, disabled conditions don't trigger, custom prize count works",
"estimatedHours": 1.5,
"notes": "Test with different RulesConfig to verify each condition can be disabled"
},
{
"id": "HIGH-007",
"name": "Create turn manager",
"description": "Implement the turn/phase state machine with valid transitions and turn start/end handling",
"category": "high",
"priority": 24,
"completed": false,
"tested": false,
"dependencies": ["HIGH-003", "CRIT-002"],
"files": [
{"path": "app/core/turn_manager.py", "issue": "File does not exist"}
],
"suggestedFix": "TurnManager class with advance_phase(), end_turn(), start_turn() methods. Enforce valid transitions (DRAW->MAIN->ATTACK->END). Handle between-turn effects (poison/burn damage). Reset per-turn flags on turn start.",
"estimatedHours": 2.5,
"notes": "State machine should be strict about valid transitions. Consider setup phase for game initialization."
},
{
"id": "TEST-011",
"name": "Create turn manager tests",
"description": "Test phase transitions, turn switching, and per-turn state resets",
"category": "high",
"priority": 25,
"completed": false,
"tested": false,
"dependencies": ["HIGH-007", "HIGH-004"],
"files": [
{"path": "tests/core/test_turn_manager.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: valid transitions work, invalid transitions rejected, turn switch alternates players, per-turn flags reset, between-turn effects applied",
"estimatedHours": 2,
"notes": "Test poison/burn damage application between turns"
},
{
"id": "HIGH-008",
"name": "Create visibility filter",
"description": "Implement hidden information filtering to create client-safe game state views",
"category": "high",
"priority": 26,
"completed": false,
"tested": false,
"dependencies": ["HIGH-003"],
"files": [
{"path": "app/core/visibility.py", "issue": "File does not exist"}
],
"suggestedFix": "VisibleGameState model with filtered data. get_visible_state(game, player_id) returns: full own hand, own prize count, opponent hand COUNT only, opponent deck COUNT only, public battlefield/discard. Never expose deck order or opponent hand contents.",
"estimatedHours": 2,
"notes": "CRITICAL SECURITY: This prevents cheating. Must never leak hidden information."
},
{
"id": "TEST-012",
"name": "Create visibility filter tests",
"description": "Test that hidden information is never leaked and public information is preserved",
"category": "high",
"priority": 27,
"completed": false,
"tested": false,
"dependencies": ["HIGH-008", "HIGH-004"],
"files": [
{"path": "tests/core/test_visibility.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: opponent hand contents not visible, opponent deck order not visible, own hand fully visible, battlefield fully visible, prize counts visible but not contents",
"estimatedHours": 1.5,
"notes": "Security-critical tests. Verify no hidden data leaks through any path."
},
{
"id": "HIGH-009",
"name": "Create main GameEngine orchestrator",
"description": "Implement the main GameEngine class that orchestrates all components: game creation, action validation, action execution, win condition checking",
"category": "high",
"priority": 28,
"completed": false,
"tested": false,
"dependencies": ["HIGH-005", "HIGH-006", "HIGH-007", "HIGH-008", "MED-002"],
"files": [
{"path": "app/core/engine.py", "issue": "File does not exist"}
],
"suggestedFix": "GameEngine class with: __init__(rules, rng_provider), create_game(player_ids, decks, card_registry), validate_action(game, player_id, action), execute_action(game, player_id, action), check_win_conditions(game), get_visible_state(game, player_id). All methods async.",
"estimatedHours": 4,
"notes": "This is the main public API. Should be the only entry point for game operations."
},
{
"id": "TEST-013",
"name": "Create GameEngine integration tests",
"description": "Test full game flow from creation through actions to win condition",
"category": "high",
"priority": 29,
"completed": false,
"tested": false,
"dependencies": ["HIGH-009", "HIGH-004"],
"files": [
{"path": "tests/core/test_engine.py", "issue": "File does not exist"}
],
"suggestedFix": "Test: create game with two players, execute valid actions, reject invalid actions, detect win condition, full sample game playthrough",
"estimatedHours": 3,
"notes": "Integration tests should cover realistic game scenarios"
},
{
"id": "MED-004",
"name": "Create core module exports",
"description": "Set up clean public API exports in __init__.py files",
"category": "medium",
"priority": 30,
"completed": false,
"tested": false,
"dependencies": ["HIGH-009"],
"files": [
{"path": "app/core/__init__.py", "issue": "Needs public API exports"},
{"path": "app/core/models/__init__.py", "issue": "Needs model exports"},
{"path": "app/core/effects/__init__.py", "issue": "Needs effect exports"}
],
"suggestedFix": "Export key classes: GameEngine, RulesConfig, GameState, CardDefinition, CardInstance, Action types, effect_handler decorator",
"estimatedHours": 0.5,
"notes": "Clean API surface for consumers of the core module"
},
{
"id": "DOCS-001",
"name": "Create core module CLAUDE.md",
"description": "Document the game engine architecture, patterns, and usage guidelines for AI agents",
"category": "low",
"priority": 31,
"completed": false,
"tested": false,
"dependencies": ["HIGH-009"],
"files": [
{"path": "app/core/CLAUDE.md", "issue": "File does not exist"}
],
"suggestedFix": "Document: module structure, key classes, effect handler pattern, configuration system, testing approach, security considerations (hidden info)",
"estimatedHours": 1,
"notes": "Reference doc as specified in CLAUDE.md"
},
{
"id": "LOW-001",
"name": "Add comprehensive docstrings",
"description": "Ensure all public classes and methods have detailed docstrings with examples",
"category": "low",
"priority": 32,
"completed": false,
"tested": false,
"dependencies": ["HIGH-009"],
"files": [
{"path": "app/core/", "issue": "Review all files for docstring coverage"}
],
"suggestedFix": "Add Google-style docstrings with Args, Returns, Raises, and Example sections",
"estimatedHours": 2,
"notes": "Good documentation enables better AI assistance and maintainability"
}
],
"quickWins": [
{
"taskId": "CRIT-001",
"estimatedMinutes": 30,
"impact": "Unblocks all other development"
},
{
"taskId": "CRIT-002",
"estimatedMinutes": 60,
"impact": "Foundation for all models"
},
{
"taskId": "MED-004",
"estimatedMinutes": 30,
"impact": "Clean public API"
}
],
"productionBlockers": [
{
"taskId": "HIGH-005",
"reason": "Cannot trust client actions without server-side validation"
},
{
"taskId": "HIGH-008",
"reason": "Hidden information must never leak to clients"
},
{
"taskId": "HIGH-009",
"reason": "No gameplay possible without engine orchestrator"
}
],
"weeklyRoadmap": {
"week1": {
"theme": "Foundation & Models",
"tasks": ["CRIT-001", "CRIT-002", "TEST-001", "CRIT-003", "TEST-002", "CRIT-004", "TEST-003"],
"estimatedHours": 8,
"goals": ["Module structure complete", "Enums, config, and RNG working with tests"]
},
"week2": {
"theme": "Core Models",
"tasks": ["HIGH-001", "TEST-004", "HIGH-002", "TEST-005", "HIGH-003", "TEST-006", "HIGH-004"],
"estimatedHours": 12,
"goals": ["All data models complete", "Test fixtures established"]
},
"week3": {
"theme": "Effects System",
"tasks": ["MED-001", "MED-002", "TEST-007", "MED-003", "TEST-008"],
"estimatedHours": 8,
"goals": ["Effect handler system working", "Built-in effects implemented"]
},
"week4": {
"theme": "Game Logic",
"tasks": ["HIGH-005", "TEST-009", "HIGH-006", "TEST-010", "HIGH-007", "TEST-011"],
"estimatedHours": 14,
"goals": ["Validation working", "Win conditions working", "Turn management working"]
},
"week5": {
"theme": "Engine & Polish",
"tasks": ["HIGH-008", "TEST-012", "HIGH-009", "TEST-013", "MED-004", "DOCS-001", "LOW-001"],
"estimatedHours": 14,
"goals": ["GameEngine complete", "Full integration tested", "Documentation complete"]
}
},
"testingStrategy": {
"unitTests": "Each module has corresponding test file",
"integrationTests": "test_engine.py covers full game flow",
"fixtures": "conftest.py provides reusable sample data",
"determinism": "SeededRandom enables reproducible random tests",
"coverage": "Target 90%+ coverage on core module"
},
"securityChecklist": [
{
"item": "Deck order never sent to client",
"module": "visibility.py",
"verified": false
},
{
"item": "Opponent hand contents never sent",
"module": "visibility.py",
"verified": false
},
{
"item": "Prize card contents hidden until taken",
"module": "visibility.py",
"verified": false
},
{
"item": "All actions validated server-side",
"module": "rules_validator.py",
"verified": false
},
{
"item": "RNG unpredictable in production",
"module": "rng.py",
"verified": false
}
]
}